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