 /**//*
題意:給出一個(gè)地圖,有K種需要采集的礦,挖掘礦,帶著礦都需要電量,分別為ai,bi,
問收集完所有種類的最少時(shí)間,一個(gè)位置的礦可采可不采,未收集完不能返回原點(diǎn)
像這種情況復(fù)雜一點(diǎn)的bfs,可以加priority_queue
可以想象,只要保證每次到達(dá)一個(gè)狀態(tài)是最優(yōu)的,那么這些狀態(tài)的和也是最優(yōu)的,包括最后到達(dá)目標(biāo)狀態(tài)
每次出隊(duì)的狀態(tài)是最優(yōu)的,在這里標(biāo)記訪問過!
狀態(tài):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;//是到達(dá)nx,ny的時(shí)間
if(vi[x][y][state]||time>P)continue;
vi[x][y][state]=1;//第一次出來的是最優(yōu)的,在這里標(biāo)記訪問過
 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;
}

|