1. 程式人生 > >勝利大逃亡(續) HDU

勝利大逃亡(續) HDU


題意:小明被抓到n*m的迷宮中,@表示小明的初始位置, ^表示迷宮出口, *表示障礙物,  ·  表示空地, A~J表示門, a~j表示鑰匙, 對應的鑰匙開對應字元的門;

問小明能否在t時間內逃出迷宮?(若在第t時間到達迷宮出口, 記為未逃出迷宮);

需要先拿到鑰匙才能開開對應門, 和一般搜尋題相比多了鑰匙和門, 首先想到要記錄位置的同時, 用二進位制鑰匙和門的狀態, 發現ME(記憶體超限), 仔細思考後, 發現不需要記錄門的狀態, 當到達門時, 只要有對應鑰匙就能過去, 沒有就過不去, 而鑰匙, 在拿著某一鑰匙和不拿, 走過相同位置是不同狀態, 而門開與不開可看做一種狀態, 可理解為有鑰匙暢通無阻, 無鑰匙寸步難行;

最後關於輸出, 不需要再單獨輸出空行, 題目要求再每個樣例之間有空行, 通過樣例可看出, 這個空行是輸入時輸入的;

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
char G[30][30];
int s_x, s_y;	
int n, m, t;
struct node{
	int x, y, tt;
	int key;
	node(){};
	node(int x0, int y0, int t0, int key0){
		x=x0, y=y0, tt=t0;
		key=key0;
	}
};
int vis[21][21][1025];
queue<node> que;
int dir[4][2]={1, 0, 0, 1, -1, 0, 0, -1};
void bfs(){
	memset(vis, 0, sizeof(vis));
	while(!que.empty()) que.pop();
	node tmp=node(s_x, s_y, 0, 0);
	que.push(tmp);
	vis[s_x][s_y][0]=1;
	while(!que.empty()){
		tmp=que.front();
		que.pop();
		if(G[tmp.x][tmp.y]=='^'){
			printf("%d\n", tmp.tt);
			return;
		}
		if(tmp.tt>=t-1) continue;
		for(int i=0; i<4; i++){
			int tx=tmp.x+dir[i][0];
			int ty=tmp.y+dir[i][1];
			int k=tmp.key;
			if(tx<0||ty<0||tx>=n||ty>=m||G[tx][ty]=='*') continue;
			if(G[tx][ty]<='z'&&G[tx][ty]>='a'&&!(k&(1<<(G[tx][ty]-'a')))){//遇到鑰匙, 拿鑰匙
				k=k+(1<<(G[tx][ty]-'a'));
			}
			if(G[tx][ty]<='Z'&&G[tx][ty]>='A'){//遇到門, 看看是否有對應鑰匙, 有就開門, 沒有就過不去;
				//printf("x:%d y:%d t:%d k:%d d:%d\n", tx, ty, tmp.tt, k, d);
				if(!(k&(1<<(G[tx][ty]-'a')))) continue;
			}
			if(vis[tx][ty][k]) continue;
			que.push(node(tx, ty, tmp.tt+1, k));
			vis[tx][ty][k]=1;
		}
	}
	printf("-1\n");
	return;
}
int main(){
	while(~scanf("%d%d%d", &n, &m, &t)){
		for(int i=0; i<n; i++){
			scanf("%s", G[i]);
			for(int j=0; j<m; j++){
				if(G[i][j]=='@') s_x=i, s_y=j;
			}
		}
		bfs();
	}
	return 0;
}