分析:不同於一般的bfs,每個點有四種狀態,用思維數組vis[x][y][d][c]來表示遍曆的資訊。
剛開始時用下面的方法來bfs的:
if( dx >= 0 && dx <M && dy >=0 && dy <N && map[dx][dy]) { if(!vis[dx][dy][i][color]) { vis[dx][dy][i][color] = true; if(abs(dir - i) == 3) time += 2; else time += 1; ....etc.. } } //以第二個範例來說明,這樣寫,首先起點的兩個狀態往→和往↓沒有標記 //然後遍曆(0,2)這個點時,自己的狀態只被標記一次,還是起點遍曆它時標記的 //但是這次它還要向下遍曆,一次還有向↓的狀態被標記 //綜上所述,上面的寫法是錯誤的,沒有把每個點的每種可能狀態都標記 //哎,還是自己思考的不夠縝密!Orz!
下面是AC的代碼:
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<queue>#define MAXN 26using namespace std;struct node{ int x,y; int color; int time; int dir; node(){} node(int a,int b,int c,int d,int e):x(a),y(b),color(c),time(d),dir(e){} friend bool operator < (const node &a,const node &b) { return a.time > b.time; }};priority_queue<node> q;//dir的0,1,2,3代表的以此是向↑,←,↓,→四個方向遍曆//color的0,1,2,3,4代表green,white,blue,red,black五種顏色,不注釋很容易看錯bool vis[MAXN][MAXN][4][5];char map[MAXN][MAXN];int move[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};int M,N;node begin,end;bool isEnd(int x,int y,int color){ if(x == end.x && y == end.y && color == end.color) return true; return false;}void bfs(node begin){ while(!q.empty()) q.pop(); q.push(begin); vis[begin.x][begin.y][begin.dir][begin.color] = true; while(!q.empty()) { node Q = q.top(); q.pop(); for(int i = 0;i<4;i++) { int dx = Q.x + move[i][0]; int dy = Q.y + move[i][1]; int dir = Q.dir; int color = Q.color; int time = Q.time; if(dx >= 0 && dx <M && dy >= 0 && dy < N && map[dx][dy] != '#') { node Temp; if(abs(dir - i) == 0 ) { time += 1; Temp = node(dx,dy,(color+1)%5,time,i); } else { if(abs(dir - i) == 2) time += 2; else time += 1; Temp = node(Q.x,Q.y,color,time,i); } if(!vis[Temp.x][Temp.y][Temp.dir][Temp.color]) { vis[Temp.x][Temp.y][Temp.dir][Temp.color] = true; if(isEnd(Temp.x,Temp.y,Temp.color)) { printf("minimum time = %d sec\n",Temp.time); return; } q.push(Temp); } } } } printf("destination not reachable\n"); return;}int main(){ int T=0; while(scanf("%d%d",&M,&N) && M && N) { T++; memset(vis,false,sizeof(vis)); int begin_x,begin_y; int end_x,end_y; for(int i = 0;i < M;i++) { scanf("%s",map[i]); for(int j = 0;j < N;j++) { if(map[i][j] == 'S') { begin_x = i; begin_y = j; } if(map[i][j] == 'T') { end_x = i; end_y = j; } } } begin = node(begin_x,begin_y,0,0,0); end = node(end_x,end_y,0,0,0); if(T !=1 ) printf("\n"); printf("Case #%d\n",T); bfs(begin); } return 0;}