分析:不同于一般的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 26
using 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;
}