PKU : 2157 - Maze
問題概要
http://poj.org/problem?id=2157
入力例のようにマップが入力されます.
- S : スタート
- G : ゴール
- X : 壁
- . : 通路
- a,b,c,d,e : カギ
- A,B,C,D,E : 扉
扉は, その扉に対応するカギを全て集めてからでないと, 開けることができません.
このとき, スタートからゴールまで辿りつけるでしょうか.
アルゴリズム
A,B,C,D,Eの扉を, 開けられる扉から開けていって, ゴールまで辿りつけるかを確かめました.
プログラム
typedef pair<int,int> P; int h,w; int sx,sy,cnt[5]; char t[22][22]; bool hav[5],closed[22][22]; int dx[] = {-1,1,0,0}; int dy[] = {0,0,1,-1}; bool check(int x,int y){ if(x < 0 || w <= x || y < 0 || h <= y || t[y][x] == 'X') return false; if(t[y][x] == 'S' || t[y][x] == 'G') return true; if(isupper(t[y][x])) return hav[t[y][x] - 'A']; return true; } //戻り値 : ゴールにたどり着いたかどうか //引数に与えられた扉が開けられるなら開ける bool bfs(int id){ queue<P> open; int keyCnt = 0; open.push(P(sx,sy)); memset(closed,0,sizeof(closed)); //BFS while(!open.empty()){ P p = open.front(); open.pop(); if(closed[p.first][p.second]) continue; closed[p.first][p.second] = true; //ゴール到着 if(t[p.second][p.first] == 'G'){ return true; } //目当てのカギがあったら拾う if(t[p.second][p.first] == id + 'a'){ keyCnt++; } rep(i,4){ int nx = p.first + dx[i]; int ny = p.second + dy[i]; if(check(nx,ny)){ open.push(P(nx,ny)); } } } //カギを全て集めていたら, 扉を開けられる if(keyCnt == cnt[id]){ hav[id] = true; } return false; } bool solve(){ memset(hav,0,sizeof(hav)); //開けられる扉を順番に開けていく rep(i,6){ rep(j,5){ bool flg = bfs(i); if(flg) return true; } } return false; } int main(void){ while(cin>>h>>w,h||w){ memset(cnt,0,sizeof(cnt)); rep(i,h){ cin>>t[i]; rep(j,w){ //アルファベットごとに, カギの数をカウント if(islower(t[i][j])){ cnt[t[i][j]-'a']++; } if(t[i][j] == 'S'){ sx = j; sy = i; } } } cout<<(solve() ? "YES" : "NO")<<endl; } }