連結:點擊開啟連結
思路:剛開始我想的是兩個bfs,來找最少的時間,就是先找門,根據門在找鑰匙。但是WA,果斷是想簡單啦。如果在找門的途中就可以找到鑰匙,就不要返回去找啦,所以我的想法錯啦。後面是看解題報告,要用二進位位元運算來做,其實標記數組加一維來計算拾到的鑰匙。發現好多題都是這個標記數組牛逼啦,太他媽神啦。。
用二進位來表示手頭的鑰匙有哪些,100表示有第三把鑰匙,111表示有第三、二、一把,搜尋下一點時,如果該點為鑰匙點,則可採用|運算來類比拾取,顯然0001 | 1000 = 1001,同理,當為相應的門時採用&運算來類比開啟,例如1101 & 0001 = 0001(即可以開啟'A'門)
#include<iostream>#include<queue>#include<cstring>#include<cstdio>using namespace std;struct node{int x;int y;int time;int nkey;};bool vis[30][30][1025];int n,m,t,a[4][2]={{0, 1}, {0, -1}, {-1, 0}, {1, 0}};;int map[30][30],fx,fy,ex,ey;void bfs(){int i,xx;queue<node>Q;node p,q;p.x=fx;p.y=fy;p.time=0;p.nkey=0;vis[p.x][p.y][p.nkey]=1;Q.push(p);while(!Q.empty()){p=Q.front();Q.pop();for(i=0;i<4;i++){q=p;q.x=p.x+a[i][0];q.y=p.y+a[i][1];q.time++; if(q.x>=1&&q.x<=n&&q.y>=1&&q.y<=m&&map[q.x][q.y]!='*'&&q.time<t){if(q.x==ex&&q.y==ey){printf("%d\n",q.time);return;}//if(q.time>t) continue; if(map[q.x][q.y]>='a'&&map[q.x][q.y]<='z'){xx=(1<<(map[q.x][q.y]-'a'));q.nkey|=xx;if(!vis[q.x][q.y][q.nkey]){vis[q.x][q.y][q.nkey]=1; Q.push(q); }} else if(map[q.x][q.y]>='A'&&map[q.x][q.y]<='Z'){ xx=(map[q.x][q.y]-'A');if(((q.nkey>>xx)&1)&&!vis[q.x][q.y][q.nkey]){vis[q.x][q.y][q.nkey]=1;Q.push(q);}} else if(!vis[q.x][q.y][q.nkey]){vis[q.x][q.y][q.nkey]=1;Q.push(q);}} }}printf("-1\n");}int main(){int i,j,k=0;while(~scanf("%d %d %d",&n,&m,&t)){//if(k!=0)//cout<<endl;//k++;for(i=1;i<=n;i++){getchar();for(j=1;j<=m;j++){scanf("%c",&map[i][j]);if(map[i][j]=='@'){fx=i;fy=j;}else if(map[i][j]=='^'){ex=i;ey=j;}}}memset(vis,0,sizeof(vis));bfs();}return 0;}