这道题是我放了好久又做的
开始的时候对vis[]数组认识不深刻,后来看到dp的记忆化搜索,这道题的思路就很容易理解了
在这道题中,其实vis记录的不是某个位置是否已经访问过,而是记录某个状态以前事都出现过。
还有就是我开始的时候总是想从某个位置开始可以一下子走向三个位置,正向的time加1,而需要左右转的time加2。
其实这样遗漏了很多情况,如在某个位置的时候正向是0,则方向2和4也同时应该标记访问过。但是我上面的思路就不能标记。
所以,这道题要一步一步的来。。。向前和左转、右转都看作一个单位完成的。
代码如下:
#include <cstdio>
#include <cstring>
#define size 100000
struct node{
int x, y, c, d;
};
int m, n, s_x, s_y, t_x, t_y, dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
bool gra[30][30], vis[30][30][6][5];
node st[size];
int step[size];
int is_ok(int x, int y)
{
if(x>=0&&x<m&&y>=0&&y<n&&gra[x][y]==0) return 1;
return 0;
}
int bfs()
{
int rear = 0, front = 1, _x, _y, _c, _d, x, y, ok = 0;
vis[s_x][s_y][0][0] = 1;
st[0].x = s_x; st[0].y = s_y; st[0].c = 0; st[0].d = 0; step[0] = 0;
while(rear<front)
{
_x = st[rear].x; _y = st[rear].y; _c = st[rear].c; _d = st[rear].d;
if(_x==t_x&&_y == t_y&&_c==0) {ok = 1; break; }
if(is_ok(x = _x+dir[_d][0], y = _y+dir[_d][1])&&vis[x][y][(_c+1)%5][_d]==0)
{
vis[x][y][(_c+1)%5][_d] = 1;
st[front].x = x;
st[front].y = y;
st[front].c = (_c+1)%5;
st[front].d = _d;
step[front] = step[rear]+1;
front++;
}
if(vis[_x][_y][_c][(_d+3)%4]==0)
{
vis[_x][_y][_c][(_d+3)%4] = 1;
st[front].x = _x;
st[front].y = _y;
st[front].c = _c;
st[front].d = (_d+3)%4;
step[front] = step[rear]+1;
front++;
}
if(vis[_x][_y][_c][(_d+1)%4]==0)
{
vis[_x][_y][_c][(_d+1)%4] = 1;
st[front].x = _x;
st[front].y = _y;
st[front].c = _c;
st[front].d = (_d+1)%4;
step[front] = step[rear]+1;
front++;
}
rear++;
}
if(ok == 1) return step[rear];
else return -1;
}
int main ()
{
char tt;
int cas = 0, ans;
while(scanf("%d%d",&m,&n),m+n)
{
getchar();
for(int i = 0; i < m; i++, getchar()) for(int j = 0; j < n; j++)
{
scanf("%c",&tt);
if(tt=='#') gra[i][j] = 1;
else if(tt=='S') {s_x = i; s_y = j; gra[i][j] = 0;}
else if(tt=='T') {t_x = i; t_y = j; gra[i][j] = 0;}
else gra[i][j] = 0;
}
memset(vis,0,sizeof(vis));
ans = bfs();
if(cas) printf("\n");
printf("Case #%d\n",++cas);
if(ans==-1) printf("destination not reachable\n");
else printf("minimum time = %d sec\n", ans);
}
return 0;
}