勝利大逃亡(續) (bfs+狀壓)
勝利大逃亡(續)
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11042 Accepted Submission(s): 4037
Problem Description
Ignatius再次被魔王抓走了(搞不懂他咋這麼討魔王喜歡)……
這次魔王汲取了上次的教訓,把Ignatius關在一個n*m的地牢裡,並在地牢的某些地方安裝了帶鎖的門,鑰匙藏在地牢另外的某些地方。剛開始Ignatius被關在(sx,sy)的位置,離開地牢的門在(ex,ey)的位置。Ignatius每分鐘只能從一個座標走到相鄰四個座標中的其中一個。魔王每t分鐘回地牢視察一次,若發現Ignatius不在原位置便把他拎回去。經過若干次的嘗試,Ignatius已畫出整個地牢的地圖。現在請你幫他計算能否再次成功逃亡。只要在魔王下次視察之前走到出口就算離開地牢,如果魔王回來的時候剛好走到出口或還未到出口都算逃亡失敗。
Input
每組測試資料的第一行有三個整數n,m,t(2<=n,m<=20,t>0)。接下來的n行m列為地牢的地圖,其中包括:
. 代表路
* 代表牆
@ 代表Ignatius的起始位置
^ 代表地牢的出口
A-J 代表帶鎖的門,對應的鑰匙分別為a-j
a-j 代表鑰匙,對應的門分別為A-J
每組測試資料之間有一個空行。
Output
針對每組測試資料,如果可以成功逃亡,請輸出需要多少分鐘才能離開,如果不能則輸出-1。
Sample Input
4 5 17 @A.B. a*.*. *..*^ c..b* 4 5 16 @A.B. a*.*. *..*^ c..b*
Sample Output
16
-1
用一個二進位制數表示當前這個點有哪幾把鑰匙,比如0011表示有1,2兩把鑰匙(a,b),如果當前這個點是門,則用&,比如0011&0010=0010說明當前這扇門能開啟,能走。
如果當前這個點是鑰匙,則用|,比如0011|1000=1011 說明到當前這個點找到了1,2,4這幾把鑰匙
1<<s[i][j]-'a',表示將1左移x位,對應第x把鑰匙
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <stack> #define rson rt<<1|1 #define lson rt<<1 using namespace std ; typedef long long LL; const int MAX = 100 ; char Map[MAX][MAX] ; int vis[50][50][2000] ; int sx ,sy ; int ex ,ey ; struct Point{ int x ; int y ; int k ;// 用來記錄當前這個點能開啟哪幾扇門,即撿到了哪幾把鑰匙 int step ; }; int dx[4] = {0,1,0,-1}; int dy[4] = {1,0,-1,0}; int n , m ,t ; int bfs(Point start ,Point end ) { queue<Point> Q ; start.step = 0 ; start.k = 0 ; vis[start.x][start.y][start.k] = 1 ; Q.push(start); while(!Q.empty()) { Point p = Q.front() ; Q.pop() ; if(Map[p.x][p.y]=='^') { if(p.step <t ) { return p.step ; } else { return 0 ; } } if(p.step>=t) return 0 ;// 當前已經過時間了 for(int k = 0 ;k<4 ;k++) { int nextx = p.x + dx[k] ; int nexty = p.y + dy[k] ; if(nexty>=0 && nextx>=0 && nextx<n &&nexty<m && Map[nextx][nexty]!='*') { Point tmp ; tmp.x = nextx ; tmp.y = nexty ; tmp.k = p.k ; tmp.step = p.step+1 ; if(Map[tmp.x][tmp.y] >='a'&& Map[tmp.x][tmp.y]<='z') { // 鑰匙 ; int key = p.k|(1<<(Map[tmp.x][tmp.y]-'a')) ; if(!vis[tmp.x][tmp.y][tmp.k]) { vis[tmp.x][tmp.y][tmp.k] = 1 ; tmp.k = key ; Q.push(tmp); } } else if(Map[tmp.x][tmp.y] >='A'&& Map[tmp.x][tmp.y]<='Z') { // 如果下一個點是門; int key = p.k&(1<<(Map[tmp.x][tmp.y]-'A')); if(!vis[tmp.x][tmp.y][tmp.k] && key) { // 如果有開啟改門的鑰匙 vis[tmp.x][tmp.y][tmp.k] = 1 ; Q.push(tmp); } } else { // 路 if(!vis[tmp.x][tmp.y][tmp.k]) { vis[tmp.x][tmp.y][tmp.k] = 1 ; Q.push(tmp) ; } } } } } return 0; } int main() { while(~scanf("%d%d%d",&n,&m,&t)){ Point start ; Point end ; memset(vis,0,sizeof(vis)) ; for(int i = 0 ; i<n ;i++) { scanf("%s",Map[i]); for(int j = 0 ;j<m ;j++) { if(Map[i][j] =='@') { sx = i ; sy = j ; start.x = i ; start.y = j ; } if(Map[i][j] == '^') { ex = i ; ey = j ; end.x = i ; end.y = j ; } } } int ans = bfs(start,end) ; if(ans) { printf("%d\n",ans); } else { printf("-1\n"); } } return 0 ; }