胜利大逃亡(续) HDU - 1429

胜利大逃亡(续)

题目链接: HDU - 1429

题意:小明被抓到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;
}





猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/80228398