AOJ - Problem 0558 : Cheese
1,2, ... , NのチーズがN個あり、1から順に食べるとき全部のチーズを食べるのに必要な最短経路を求める問題です(Nは9以下)。必ず全てのチーズが食べられることが保証されているようです。またフィールドの幅と高さw,hは1000以下となっています。
幅優先探索(BFS)で解くことのできる問題です。スタートからチーズ1まで最短経路、チーズ1からチーズ2までの最短経路, ... , チーズn-1からチーズnまでの最短経路とそれぞれ求めましょう。
探索するときは配列dについてd[y][x]にスタートから(x,y)まで最短経路の値を入れるようにします。初めに配列dのすべてのマスのINF(非常に大きい数)で初期化し、INFをまだ探索していないマスとして扱います。スターとから順に探索し、探索していないマス(値がINF)だったらその都度配列dの値を更新します。
#include <iostream> #include <queue> #include <map> #include <iostream> using namespace std; struct p{ int x, y; }; typedef struct p P; const int INF = 1e+7; int dx[4] = {0,0,1,-1}; int dy[4] = {1,-1,0,0}; int w,h,n; string m[1001]; P cheese[11]; int ans = 0; int d[1001][1001]; void bfs(){ for(int i=1 ; i <= n ; i++ ){ P sp = cheese[i-1]; int sx = cheese[i-1].x; int sy = cheese[i-1].y; int gx = cheese[i].x; int gy = cheese[i].y; for(int y=0 ; y < h ; y++ ){ for(int x=0 ; x < w ; x++ ){ d[y][x] = INF; } } queue<P> q; q.push( sp ); d[sy][sx] = 0; while( !q.empty() ){ P now = q.front(); q.pop(); int x = now.x; int y = now.y; if( x == gx && y == gy ){ ans += d[gy][gx]; break; } for(int i=0 ; i < 4 ; i++ ){ int mx = x + dx[i]; int my = y + dy[i]; if( mx < 0 || my < 0 || mx >= w || my >= h ) continue; if( m[my][mx] != 'X' ){ P next; next.x = mx; next.y = my; if( d[my][mx] == INF ){ d[my][mx] = d[y][x] + 1; q.push( next ); } } } } } } int main(){ cin >> h >> w >> n; for(int y=0 ; y < h ; y++ ){ cin >> m[y]; } for(int y=0 ; y < h ; y++ ){ for(int x=0 ; x < w ; x++ ){ char c = m[y][x]; if( c == 'S' ){ cheese[0].x = x; cheese[0].y = y; } if( c >= '1' && c <= '9' ){ cheese[ c - '0' ].x = x; cheese[ c - '0' ].y = y; } } } bfs(); cout << ans << endl; }