1. 程式人生 > >勝利大逃亡(續) (bfs+狀壓)

勝利大逃亡(續) (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  ;
}