题目:http://acm.hit.edu.cn/hoj/problem/view?id=1020
这题写出来有一种畅快感。毕竟有一个Bug Debug了好久。
if((i == 0 || i == 2) && map[tempx][tempy] == '|') continue;
我写成了: if(i == 0 || i == 2 && map[tempx][tempy] == '|') continue;
我写成了: if(i == 0 || i == 2 && map[tempx][tempy] == '|') continue;
都是粗心导致的。
本题是BFS+模拟。模拟的成分大些,主要有好多规则需要考虑到。如果遇到交叉路口或者转折点就绕过去,所以进入队列的都是'-' or '|'.只不过加了时间停顿和方向改变。
另外本题提供了BFS解决最短路问题的一种途径,以前没有这么深刻过:以前求最短路的时候,节点没有停顿,所以用vis标记的话,已经标记过的肯定就是离源点最近的,但是本题节点有停顿,所以就不一定,所以不能用vis标记。其实可以换一种思路,别忘了dist[][]数组,这可是利器,dist[i][j] == 0,说明map[i][j]还没有访问过;如果dist[i][j] !=0说明访问过,但是不一定是离源点最近的,我们可以更新他,如果更新求出的dist[i][j]比现在的要小,那么就更新,持续下去,直到队列为空,dist[i][j]就是最优情况。
另外本题求在红灯前的等待时间的算法有点傻,枚举得到的,应该可以有更精巧的手段。
代码略长。凑合看。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <queue>
using namespace std;
struct Point
{
int x;
int y;
};
Point s;
char map[105][105];
int dist[105][105];
int disx[4] = {0,1,0,-1};
int disy[4] = {1,0,-1,0};
int n,m;
//确定在当前交叉路口需要等多长时间
//参数依次为:驶入方向,从出发到此的时间,交叉路口X,交叉路口Y
//in :0-西方,1-南方,2-东方,3-北方
int waitSeconds(int in,int time,int x,int y)
{
time--;
int bet = map[x][y] - '1' + 1;
int kind,n;
int cur,rest;
//西北东方向
if(map[x+1][y]!='|') kind = 2,n = 3;
//北东南方向
else if(map[x][y-1]!='-') kind = 3,n = 3;
//东南西方向
else if(map[x-1][y]!='|') kind = 4,n = 3;
//南西北方向
else if(map[x][y+1]!='-') kind = 5,n = 3;
//东南西北方向
else kind = 1,n = 4;
cur = (time/bet) % n;
rest = bet - time % bet;
//in == 西方
if(in == 0 && kind == 1)
{
if(cur == 0) return rest + 2 * bet;
if(cur == 1) return rest + bet;
if(cur == 2) return rest;
if(cur == 3) return 0;
}
else if(in == 0 && kind == 2)
{
if(cur == 0) return rest;
if(cur == 1) return 0;
if(cur == 2) return rest + bet;
}
else if(in == 0 && kind == 4)
{
if(cur == 0) return rest + bet;
if(cur == 1) return rest;
if(cur == 2) return 0;
}
else if(in == 0 && kind == 5)
{
if(cur == 0) return rest + bet;
if(cur == 1) return rest;
if(cur == 2) return 0;
}
//in == 南方
else if(in == 3 && kind == 1)
{
if(cur == 0) return 0;
if(cur == 1) return rest + 2 * bet;
if(cur == 2) return rest + bet;
if(cur == 3) return rest;
}
else if(in == 3 && kind == 3)
{
if(cur == 0) return 0;
if(cur == 1) return rest + bet;
if(cur == 2) return rest;
}
else if(in == 3 && kind == 4)
{
if(cur == 0) return 0;
if(cur == 1) return rest + bet;
if(cur == 2) return rest;
}
else if(in == 3 && kind == 5)
{
if(cur == 0) return 0;
if(cur == 1) return rest + bet;
if(cur == 2) return rest;
}
//in == 东方
else if(in == 2 && kind == 1)
{
if(cur == 0) return rest;
if(cur == 1) return 0;
if(cur == 2) return rest + 2 * bet;
if(cur == 3) return rest + bet;
}
else if(in == 2 && kind == 2)
{
if(cur == 0) return rest + bet;
if(cur == 1) return rest;
if(cur == 2) return 0;
}
else if(in == 2 && kind == 3)
{
if(cur == 0) return rest;
if(cur == 1) return 0;
if(cur == 2) return rest + bet;
}
else if(in == 2 && kind == 4)
{
if(cur == 0) return rest;
if(cur == 1) return 0;
if(cur == 2) return rest + bet;
}
//in == 北方
else if(in == 1 && kind == 1)
{
if(cur == 0) return rest + bet;
if(cur == 1) return rest;
if(cur == 2) return 0;
if(cur == 3) return rest + 2 * bet;
}
else if(in == 1 && kind == 2)
{
if(cur == 0) return 0;
if(cur == 1) return rest + bet;
if(cur == 2) return rest;
}
else if(in == 1 && kind == 3)
{
if(cur == 0) return rest + bet;
if(cur == 1) return rest;
if(cur == 2) return 0;
}
else if(in == 1 && kind == 5)
{
if(cur == 0) return rest;
if(cur == 1) return 0;
if(cur == 2) return rest + bet;
}
else
{
return 0;
}
}
int bfs()
{
queue<Point> p;
Point temp,nex;
p.push(s);
dist[s.x][s.y] = 1;
int max = 0x3f3f3f3f;
while(!p.empty())
{
//temp肯定是'-'或者'|'或者'S'
temp = p.front();
p.pop();
//从右开始顺时针遍历
for(int i=0; i<4; i++)
{
int tempx = temp.x + disx[i];
int tempy = temp.y + disy[i];
if(map[temp.x][temp.y] == 'S')
{
if((i == 0 || i == 2) && map[tempx][tempy] == '|') continue;
if((i == 1 || i == 3) && map[tempx][tempy] == '-') continue;
}
else if(map[temp.x][temp.y] == '-')
{
if(i == 1 || i== 3) continue;
if((i == 0 || i == 2) && map[tempx][tempy] == '|') continue;
}
else if(map[temp.x][temp.y] == '|')
{
if(i == 0 || i== 2) continue;
if((i == 1 || i == 3) && map[tempx][tempy] == '-') continue;
}
if(tempx>=1 && tempx<=n && tempy>=1 && tempy<=m)
{
if(map[tempx][tempy]!='*' && map[tempx][tempy]!=' ')
{
//交叉口
if(map[tempx][tempy] >='1' && map[tempx][tempy]<='9')
{
//计算在当前灯前需要停留多长时间
int wait = waitSeconds(i,dist[temp.x][temp.y],tempx,tempy);
int tx = tempx;
int ty = tempy;
//越过交叉口
for(int j=0; j<4; j++)
{
tempx = tx + disx[j];
tempy = ty + disy[j];
if(map[temp.x][temp.y] == '-')
{
if((j == 1 || j== 3) && map[tempx][tempy] == '-') continue;
if((j == 0 || j == 2) && map[tempx][tempy] == '|') continue;
}
else if(map[temp.x][temp.y] == '|')
{
if((j == 1 || j== 3) && map[tempx][tempy] == '-') continue;
if((j == 0 || j == 2) && map[tempx][tempy] == '|') continue;
}
if(tempx>=1 && tempx<=n && tempy>=1 && tempy<=m)
{
if(map[tempx][tempy]!='*' && map[tempx][tempy]!=' ')
{
nex.x = tempx;
nex.y = tempy;
if(dist[nex.x][nex.y] == 0 || (dist[nex.x][nex.y] > dist[temp.x][temp.y] + 1 + wait))
{
dist[nex.x][nex.y] = wait + dist[temp.x][temp.y] + 1;
if(map[nex.x][nex.y] == 'D')
{
if(dist[nex.x][nex.y] < max) max = dist[nex.x][nex.y];
}
else p.push(nex);
}
}
}
}
}
//转折点
else if(map[tempx][tempy] == '+')
{
int tx = tempx;
int ty = tempy;
for(int j=0; j<4; j++)
{
tempx = tx + disx[j];
tempy = ty + disy[j];
if(map[temp.x][temp.y] == '-')
{
if((j == 1 || j== 3) && map[tempx][tempy] == '-') continue;
if((j == 0 || j == 2) && map[tempx][tempy] == '|') continue;
}
else if(map[temp.x][temp.y] == '|')
{
if((j == 1 || j== 3) && map[tempx][tempy] == '-') continue;
if((j == 0 || j == 2) && map[tempx][tempy] == '|') continue;
}
if(tempx>=1 && tempx<=n && tempy>=1 && tempy<=m)
{
if(map[tempx][tempy]!='*' && map[tempx][tempy]!=' ')
{
nex.x = tempx;
nex.y = tempy;
if(dist[nex.x][nex.y] == 0 || (dist[nex.x][nex.y] > dist[temp.x][temp.y] + 1))
{
dist[nex.x][nex.y] = dist[temp.x][temp.y] + 1;
if(map[nex.x][nex.y] == 'D')
{
if(dist[nex.x][nex.y] < max) max = dist[nex.x][nex.y];
}
else p.push(nex);
}
}
}
}
}
//必须是同一方向的路段
else if(map[tempx][tempy] == map[temp.x][temp.y] || map[temp.x][temp.y] == 'S' || map[tempx][tempy] == 'S')
{
nex.x = tempx,nex.y = tempy;
if(dist[nex.x][nex.y] == 0 || (dist[nex.x][nex.y] > dist[temp.x][temp.y] + 1))
{
dist[nex.x][nex.y] = dist[temp.x][temp.y] + 1;
p.push(nex);
}
}
else if(map[tempx][tempy] == 'D')
{
if(dist[temp.x][temp.y] + 1 < max) max = dist[temp.x][temp.y] + 1;
}
}
}
}
}
return max;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int t;
scanf(" %d",&t);
while(t--)
{
scanf(" %d %d",&n,&m);
memset(map,0,sizeof(map));
memset(dist,0,sizeof(dist));
char c;
scanf("%c",&c);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
scanf("%c",&map[i][j]);
if(map[i][j] == 'S')
{
s.x = i;
s.y = j;
}
}
scanf("%c",&c);
}
int ans = bfs();
if(ans == 0x3f3f3f3f)
{
printf("impossible\n");
}
else
{
printf("%d\n",ans - 2);
}
}
return 0;
}