诡异的楼梯
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 8913 Accepted Submission(s): 2205
Problem Description
Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向.
比如下面的例子里,一开始楼梯在竖直方向,一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)告诉Harry正好有一个魔法道具可以帮助他寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.
比如下面的例子里,一开始楼梯在竖直方向,一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)告诉Harry正好有一个魔法道具可以帮助他寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.
Input
测试数据有多组,每组的表述如下:
第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.
第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.
Output
只有一行,包含一个数T,表示到达目标的最短时间.
注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.
注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.
Sample Input
5 5
**..T
**.*.
..|..
.*.*.
S....
Sample Output
7
地图如下:
![](http://acm.hdu.edu.cn/data/images/C6-1003.gif)
Hint
Hint![](http://acm.hdu.edu.cn/data/images/C6-1003.gif)
就是遇到楼梯如果对面的已经访问过,就不用走了,如果对面的没有访问过,如果能直接过,能一下子走2格,如果不能直接过,等楼梯移过来,因为这样时间跟走过去相同,
也不会多。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <cstdio> 5 #include <queue> 6 using namespace std; 7 #define maxn 25 8 char mp[maxn][maxn]; 9 int vis[maxn][maxn], M, N, sx, sy, tx, ty, ans; 10 int dir[4][2] = {{0,1}, {0,-1}, {-1,0},{1,0}}; //4个方向 11 struct node{ 12 int x, y, t; 13 }; 14 bool judge(int x, int y){ 15 if(x >= 0 && x < M && y >= 0 && y < N && mp[x][y] != '*' && !vis[x][y]) return 1; 16 return 0; 17 } 18 bool judgeBridge(int x, int y, int t, int dir){ //注意这里要算前一秒的!!!!因为还没走 19 if(mp[x][y] == '|') //如果一开始是竖的话 20 { 21 if(t%2==0 && (dir == 2 || dir == 3)) //如果还是竖的,且走的也是竖的 22 return 1 ; 23 else if(t%2 && (dir == 0 || dir == 1)) //如果是横的而且走的也是横的, 24 return 1 ; 25 } 26 else if(mp[x][y] == '-') //如果一开始是横的话 27 { 28 if(t%2==0 && (dir == 0 || dir == 1)) //如果还是横的,且走的也是横的 29 return 1; 30 else if(t%2 && (dir == 2 || dir == 3)) 31 return 1; 32 } 33 return 0; 34 } 35 node q[maxn*maxn]; 36 int BFS(int sx, int sy){ 37 memset(vis, 0, sizeof(vis)); 38 int front = 0, rear = 1; 39 q[front].x = sx; q[front].y = sy; q[front].t = 0; 40 vis[sx][sy] = 1; 41 while(front < rear){ 42 int x = q[front].x; 43 int y = q[front].y; 44 int t = q[front].t; 45 front++; 46 if(x == tx && y == ty) return t; //如果已经到了终点,跳出 47 for(int i = 0; i < 4; i++){ 48 int nx = x+dir[i][0]; 49 int ny = y+dir[i][1]; 50 if(judge(nx, ny)){ 51 if(mp[nx][ny] == '.'){ 52 vis[nx][ny] = 1; 53 node temp; 54 temp.x = nx; 55 temp.y = ny; 56 temp.t = t+1; 57 q[rear++] = temp; 58 } 59 else{ 60 int nnx = nx + dir[i][0]; 61 int nny = ny + dir[i][1]; //过桥 62 if(judge(nnx, nny)){ //如果桥对面的点没有访问过的话 63 if(judgeBridge(nx, ny, t,i )){ //过桥 64 vis[nnx][nny] = 1; 65 node temp; 66 temp.x = nnx; 67 temp.y = nny; 68 temp.t = t+1; 69 q[rear++] = temp; 70 } 71 else{ //等待 72 node temp; 73 temp.x = x; 74 temp.y = y; 75 temp.t = t+1; 76 q[rear++] = temp; 77 } 78 } 79 } 80 } 81 } 82 83 } 84 return -1; 85 } 86 int main(){ 87 while(~scanf("%d%d", &M, &N)){ 88 for(int i = 0; i < M; i++){ 89 for(int j = 0; j < N; j++){ 90 cin>>mp[i][j]; 91 } 92 } 93 for(int i = 0; i < M; i++){ 94 for(int j = 0; j < N; j++){ 95 if(mp[i][j] == 'S'){ 96 mp[i][j] = '.'; 97 sx = i; sy = j; 98 } 99 if(mp[i][j] == 'T'){ 100 mp[i][j] ='.'; 101 tx = i; ty = j; 102 } 103 } 104 } 105 106 ans = BFS(sx, sy); 107 printf("%d ", ans); 108 } 109 110 return 0; 111 }
根据这题来个BFS模板吧
1 int bfs(int sx,int sy) //初始位置 2 { 3 memset(vis, 0 ,sizeof(vis)); //清空访问数组 4 int head = 0,tail=1; //头是0, 尾是1, 因为要加入一个数,就是初始位置 5 que[head].x=sx ,que[head].y=sy ,que[head].step = 0; //把初始位置加入队列。 6 vis[sx][sy] = 1 ; //初始位置标记已经访问过 7 while(head < tail) //当队列不为空的时候 8 { 9 int x = que[head].x; 10 int y = que[head].y; 11 int step = que[head].step; //拿出队首元素 12 head++ ; //弹出 13 if(x == ex && y == ey) //如果已经走到终点,退出循环 14 { 15 return step ; 16 } 17 //如果没有结束 18 for(int i = 0 ; i < 4 ;i++){ //走上下左右4个方向 19 int nx = x+d[i][0] 20 int ny = y+d[i][1] ; 21 if(judge(nx, ny)){ //判断满足的条件 ,如果可以走 22 if(map[nx][ny] == '.'){ //如果不是楼梯直接入列 23 vis[nx][ny] = 1 ; //标记已经访问过 24 que[tail].x = nx ; 25 que[tail].y = ny ; 26 que[tail].step = step+1 ; 27 tail++; //加入队列 28 } 29 else//如果是楼梯 30 { 31 int nnx = nx + d[i][0] , nny = ny + d[i][1] ; 32 //楼梯对面的点没有访问过 33 if(judge(nnx, nny)) 34 { 35 if(goStair(nx, ny, step,i)) 36 //判断楼梯此时是否可走 37 { 38 //如果可走则直接将该点放入队列,标记为已访问 39 vis[nnx][nny] = 1; 40 que[tail].x = nnx ; 41 que[tail].y = nny; 42 que[tail].step = step+1 ; 43 tail++ ; 44 } 45 else 46 { 47 //如果此时楼梯不能走,则将此时所在的点放回队尾(等待) 48 que[tail].x = x ; 49 que[tail].y = y ; 50 que[tail].step = step+1 ; 51 tail++ ; 52 } 53 } 54 } 55 } 56 } 57 } 58 return -1 ; 59 }