勝利大逃亡(續) HDU
阿新 • • 發佈:2019-01-29
題意:小明被抓到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; }