 /**//*
题意:给出一个地图,有K种需要采集的矿,挖掘矿,带着矿都需要电量,分别为ai,bi,
问收集完所有种类的最少时间,一个位置的矿可采可不采,未收集完不能返回原点
像这种情况复杂一点的bfs,可以加priority_queue
可以想象,只要保证每次到达一个状态是最优的,那么这些状态的和也是最优的,包括最后到达目标状态
每次出队的状态是最优的,在这里标记访问过!
状态:x,y,state(state表示收集了多少种,可用位压缩)
*/
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

struct Pos
  {
int x,y,time,state;
Pos(int xx,int yy,int t,int kk)
 {
x=xx;y=yy;time=t;state=kk;
}
 bool operator<(const Pos &a)const {
return time>a.time;
}
};

 int dir[4][2]= {
 {0,1}, {1,0}, {0,-1}, {-1,0}
};
char net[30][30];
bool vi[30][30][(1<<11)+5];
int sx,sy,R,C,K,P;
int a[11],b[11],cost[(1<<11)+5];

inline bool chk(int x,int y)
  {
return x>=0&&x<R&&y>=0&&y<C;
}
int bfs()
  {
memset(vi,0,sizeof(vi));
priority_queue<Pos>Q;
Q.push(Pos(sx,sy,0,0));
 while(!Q.empty()) {
Pos top=Q.top();Q.pop();
int x=top.x,y=top.y,state=top.state,time=top.time+cost[state]+1;//是到达nx,ny的时间
if(vi[x][y][state]||time>P)continue;
vi[x][y][state]=1;//第一次出来的是最优的,在这里标记访问过
 for(int k=0;k<4;k++) {
int nx=x+dir[k][0],ny=y+dir[k][1];
if(!chk(nx,ny)||net[nx][ny]=='#'||vi[nx][ny][state])continue;
 if(nx==sx&&ny==sy) {
if(state==(1<<K)-1)return time;
continue;
}
 if(net[nx][ny]<='Z'&&net[nx][ny]>='A') {//可采可不采
int t=net[nx][ny]-'A';
 if((state&(1<<t))==0) {
if(!vi[nx][ny][state|(1<<t)]&&time+a[t]<=P)
Q.push(Pos(nx,ny,time+a[t],state|(1<<t)));
}
}
Q.push(Pos(nx,ny,time,state));
}
}
return -1;
}
int main()
  {
int T;
scanf("%d",&T);
 while(T--) {
scanf("%d%d%d%d",&R,&C,&K,&P);
 for(int i=0;i<R;i++) {
getchar();
 for(int j=0;j<C;j++) {
net[i][j]=getchar();
if(net[i][j]=='*')sx=i,sy=j;
}
}
for(int i=0;i<K;i++)
scanf("%d%d",&a[i],&b[i]);

memset(cost,0,sizeof(cost));
for(int t=0;t<(1<<K);t++)
for(int j=0;j<K;j++)
if(t&(1<<j))cost[t]+=b[j];
int ans=bfs();
if(ans==-1)puts("Impossible");
else printf("%d\n",ans);
}
return 0;
}

|