这道题目消耗了我不少时间,通过这道题目的解答,我对于广度优先搜索的理解更加深刻了,在BFS里面,每一次对于下一步状态的拓展并不是像以前的简单BFS一样仅仅局限于在位置上的更新,而应该扩展到下一步所有可能到达的状态,例如这道题里面状态由四个维度上的值决定:X坐标,Y坐标,方向,颜色,所以应该用一个四维数组来维护BFS的访问矩阵,并且我深刻理解到,每一次状态的拓展的粒度必须要分到最细,因为一开始的时候写的程序里面每一次拓展状态的时候都是发生了位移的,其实这样分解状态的粒度不够细,造成了多次WRONG ANSWER,但是一直找不到原因在哪,后来恍然大悟,每一次的状态变化只能针对一个维度上的状态发生变化,不能够既移动又旋转,每一次要么向前一步,要么原地旋转,不能够把两种状态变化同时放在一次的状态拓展中。
#include <stdio.h>
#include <string.h>
#include <queue>
#include <functional>
#include <algorithm>
using namespace std;
#define MAX 30
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
#define GREEN 0
#define BLACK 1
#define RED 2
#define BLUE 3
#define WHITE 4
int start_i, start_j;
int end_i, end_j;
char arr[MAX][MAX];
int visited[MAX][MAX][4][5];
int m, n;
int case_count;
char direc[4][10] = {"up", "down", "left", "right"};
char color[5][10] = {"green", "black", "red", "blue", "white"};
struct state
{
int i;
int j;
int direc;
int color;
};
bool operator < (const struct state &a, const struct state &b)
{
return visited[a.i][a.j][a.direc][a.color] > visited[b.i][b.j][b.direc][b.color];
}
priority_queue< struct state, vector<struct state>, less<struct state> > q;
bool is_overflow(int i, int j)
{
if( !(i>=1 && i<=m) )
return true;
if( !(j>=1 && j<=n) )
return true;
return false;
}
/*
void print_sta(struct state &sta)
{
printf("(%d,%d,%s,%s)\n", sta.i, sta.j, direc[sta.direc], color[sta.color]);
}
*/
void bfs(int i, int j, int direc, int color)
{
//while(!q.empty()) q.pop();
priority_queue< struct state, vector<struct state>, less<struct state> > q;
int min_step;
struct state sta;
int cur_i, cur_j, cur_direc, cur_color;
sta.i = i; sta.j = j; sta.direc = direc; sta.color = color;
visited[i][j][direc][color] = 1;
q.push(sta);
min_step = 0;
while(!q.empty())
{
cur_i = q.top().i;
cur_j = q.top().j;
cur_direc = q.top().direc;
cur_color = q.top().color;
q.pop();
if(cur_i==end_i && cur_j==end_j && cur_color==GREEN)
{
min_step = visited[cur_i][cur_j][cur_direc][cur_color];
break;
}
if(cur_direc == UP)
{
//这是前进一步的状态
if(!is_overflow(cur_i-1,cur_j) && arr[cur_i-1][cur_j]!='#')
{
if(visited[cur_i-1][cur_j][UP][(cur_color+1)%5] == 0)
{
visited[cur_i-1][cur_j][UP][(cur_color+1)%5] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i-1; sta.j=cur_j; sta.direc=UP; sta.color=(cur_color+1)%5;
q.push(sta);
//print_sta(sta);
}
}
//这是旋转的下一步的状态
if(visited[cur_i][cur_j][DOWN][cur_color] == 0)
{
visited[cur_i][cur_j][DOWN][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+2;
sta.i=cur_i; sta.j=cur_j; sta.direc=DOWN; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][LEFT][cur_color] == 0)
{
visited[cur_i][cur_j][LEFT][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=LEFT; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][RIGHT][cur_color] == 0)
{
visited[cur_i][cur_j][RIGHT][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=RIGHT; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
}
if(cur_direc == DOWN)
{
//这是前进一步的状态
if(!is_overflow(cur_i+1,cur_j) && arr[cur_i+1][cur_j]!='#')
{
if(visited[cur_i+1][cur_j][DOWN][(cur_color+1)%5] == 0)
{
visited[cur_i+1][cur_j][DOWN][(cur_color+1)%5] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i+1; sta.j=cur_j; sta.direc=DOWN; sta.color=(cur_color+1)%5;
q.push(sta);
//print_sta(sta);
}
}
//这是旋转的下一步的状态
if(visited[cur_i][cur_j][UP][cur_color] == 0)
{
visited[cur_i][cur_j][UP][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+2;
sta.i=cur_i; sta.j=cur_j; sta.direc=UP; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][LEFT][cur_color] == 0)
{
visited[cur_i][cur_j][LEFT][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=LEFT; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][RIGHT][cur_color] == 0)
{
visited[cur_i][cur_j][RIGHT][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=RIGHT; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
}
if(cur_direc == LEFT)
{
//这是前进一步的状态
if(!is_overflow(cur_i,cur_j-1) && arr[cur_i][cur_j-1]!='#')
{
if(visited[cur_i][cur_j-1][LEFT][(cur_color+1)%5] == 0)
{
visited[cur_i][cur_j-1][LEFT][(cur_color+1)%5] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j-1; sta.direc=LEFT; sta.color=(cur_color+1)%5;
q.push(sta);
//print_sta(sta);
}
}
//这是旋转的下一步的状态
if(visited[cur_i][cur_j][RIGHT][cur_color] == 0)
{
visited[cur_i][cur_j][RIGHT][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+2;
sta.i=cur_i; sta.j=cur_j; sta.direc=RIGHT; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][UP][cur_color] == 0)
{
visited[cur_i][cur_j][UP][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=UP; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][DOWN][cur_color] == 0)
{
visited[cur_i][cur_j][DOWN][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=DOWN; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
}
if(cur_direc == RIGHT)
{
//这是前进一步的状态
if(!is_overflow(cur_i,cur_j+1) && arr[cur_i][cur_j+1]!='#')
{
if(visited[cur_i][cur_j+1][RIGHT][(cur_color+1)%5] == 0)
{
visited[cur_i][cur_j+1][RIGHT][(cur_color+1)%5] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j+1; sta.direc=RIGHT; sta.color=(cur_color+1)%5;
q.push(sta);
//print_sta(sta);
}
}
//这是旋转的下一步的状态
if(visited[cur_i][cur_j][LEFT][cur_color] == 0)
{
visited[cur_i][cur_j][LEFT][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+2;
sta.i=cur_i; sta.j=cur_j; sta.direc=LEFT; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][UP][cur_color] == 0)
{
visited[cur_i][cur_j][UP][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=UP; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
if(visited[cur_i][cur_j][DOWN][cur_color] == 0)
{
visited[cur_i][cur_j][DOWN][cur_color] = visited[cur_i][cur_j][cur_direc][cur_color]+1;
sta.i=cur_i; sta.j=cur_j; sta.direc=DOWN; sta.color=cur_color;
q.push(sta);
//print_sta(sta);
}
}
}
printf("Case #%d\n", case_count);
if(min_step == 0)
printf("destination not reachable\n");
else
printf("minimum time = %d sec\n", min_step-1);
}
void func(int m, int n)
{
::m = m; ::n = n;
memset((void*)visited[0][0][0], 0, sizeof(int)*MAX*MAX*4*5);
bfs(start_i, start_j, UP, GREEN);
}
int main(void)
{
int m, n;
int i, j;
//freopen("input.dat", "r", stdin);
case_count = 0;
while(1)
{
scanf("%d %d", &m, &n);
getchar();
if(!m && !n)
break;
for(i=1; i<=m; i++)
{
for(j=1; j<=n; j++)
{
arr[i][j] = getchar();
if(arr[i][j] == 'S')
{ start_i = i; start_j = j; }
if(arr[i][j] == 'T')
{ end_i = i; end_j = j; }
}
getchar();
}
case_count ++;
if(case_count >= 2)
printf("\n");
func(m, n);
}
return 0;
}