AOJ : 2089 - Mysterious Dungeons
問題概要
http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=2089
小文字のアルファベットを踏むと, そのアルファベットの大文字にあたる場所が歩ける場所に変化.
さらに踏むと, 岩に変化 -> さらに踏むと, 歩ける場所に変化 -> ...
このとき, スタート地点('@') からゴール地点('<') まで, 最小歩数がいくらかを求める問題です.
もし, そのような解がなければ -1 を出力します.
アルゴリズム
次の状態を持つクラスを作って, ダイクストラで解きました.
- 現在の x 座標
- 現在の y 座標
- 現在の歩数
- 大文字のアルファベットの位置の中で歩ける場所 (ビット管理)
解説見ると, 幅優先で十分だったって!
あはは.
そんなにコードの長さ変わらないだろうから別にいいや.
プログラム
#include <iostream> #include <queue> #include <cstring> #include <map> using namespace std; class P{ public: int x,y,cost,bit; P(int _x,int _y,int _cost,int _bit){ x = _x; y = _y; cost = _cost; bit = _bit; } bool operator<(const P &p)const{ return cost > p.cost; } }; int w,h; int s[32][32]; char t[32][32]; int dx[] = {-1,1,0,0}; int dy[] = {0,0,-1,1}; int solve(int sx,int sy){ priority_queue<P> open; map< int, map<int, map<int, bool> > > closed; open.push(P(sx,sy,0,0)); while(!open.empty()){ P p = open.top(); open.pop(); if(closed[p.x][p.y][p.bit]) continue; closed[p.x][p.y][p.bit] = true; if(t[p.y][p.x] == '<'){ return p.cost; } for(int i=0;i<4;i++){ int nx = p.x + dx[i]; int ny = p.y + dy[i]; if(t[ny][nx]=='#') continue; //小文字 ... 岩状態のbit反転 if(s[ny][nx] < 0){ open.push(P(nx,ny,p.cost+1,(p.bit ^ (1<<(-s[ny][nx]))))); } //大文字 else if(s[ny][nx] > 0){ if( (p.bit & (1<<s[ny][nx])) != 0 ){ open.push(P(nx,ny,p.cost+1,p.bit)); } } else{ open.push(P(nx,ny,p.cost+1,p.bit)); } } } return -1; } int main(void){ while(cin>>w>>h && (w||h)){ int sx,sy; int alpha[26],size=1; memset(alpha,-1,sizeof(alpha)); memset(s,0,sizeof(s)); for(int i=0;i<h;i++){ cin>>t[i]; for(int j=0;j<w;j++){ if('A' <= t[i][j] && t[i][j] <= 'Z'){ int idx = t[i][j] - 'A'; if(alpha[idx] == -1){ alpha[idx] = size++; } t[i][j] = '.'; s[i][j] = alpha[idx]; } else if('a' <= t[i][j] && t[i][j] <= 'z'){ int idx = t[i][j] - 'a'; if(alpha[idx] == -1){ alpha[idx] = size++; } t[i][j] = '.'; s[i][j] = -alpha[idx]; } else if(t[i][j] == '@'){ sx = j; sy = i; } } } cout<<solve(sx,sy)<<endl; } return 0; }