胜利大逃亡(续)
题目链接: 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;
}