诡异的楼梯
Time Limit: 2000/1000 MS
(Java/Others) Memory Limit: 131072/65536 K
(Java/Others)
Total Submission(s): 7642 Accepted
Submission(s): 1830
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
Hint
Hint
Source
Recommend
bfs广搜。
在广搜的基础框架之上加了一个“会旋转的楼梯”,楼梯有2个初始状态 “|” 和 “-”
,每移动一次楼梯就变化一次(| => - ; - =>
|)。每移动一次用时一分钟,如果遇到楼梯时,正好能通过,则直接跳到楼梯对面,时间+1(也就是说2个格子只用了1分钟);如果恰好不能通过,则在原地等待1分钟。问从初始位置(S)到终点(T)的最短时间。
这道题的重点是遇到楼梯的处理,可以先用遇到楼梯时的步数(step)来判断,然后用遇到楼梯时的方向(i)来判断。
处理方法如下:
1 if | //遇到的楼梯初始是‘|’
2 if step是奇数,变化
3 if i 是奇数
4 不能通过
5 else
6 能通过
7 else //不变
8 if i 是奇数
9 能通过
10 else
11 不能通过
12 if - //遇到的楼梯初始是‘-’
13 if step是奇数,变化
14 if i 是奇数
15 能通过
16 else
17 不能通过
18 else //不变
19 if i 是奇数
20 不能通过
21 else
22 能通过
另外注意两点:
1.剪枝。有一个可以剪枝的地方:遇到楼梯先判断楼梯对面是否走过,如果已经走过,直接退出本次循环。
2.超时问题。一定要处理好step(遇到楼梯时的步数),因为step是会变的,所以这次如果不能通过,下次也一定能通过。像我一开始把“step”整成了不会变的,测试结果对了,提交却一直超时。
代码:
1 #include <iostream>
2 #include <queue>
3 #include <string.h>
4 using namespace std;
5 char a[21][21];
6 bool isw[21][21];
7 int dx[4] = {0,1,0,-1};
8 int dy[4] = {1,0,-1,0};
9 int M,N;
10 int startx,starty;
11 bool pass; //能否通过*
12 struct NODE{
13 int x;
14 int y;
15 int step;
16 };
17 int abs(int n)
18 {
19 return n>0?n:-n;
20 }
21 bool judge(int x,int y,int i,int step)
22 {
23 if( x<1 || y<1 || x>M ||y>N ) //越界
24 return 1;
25 if( isw[x][y] ) //走过了
26 return 1;
27 if( a[x][y]==‘*‘ ) //遇到墙
28 return 1;
29 if( a[x][y]==‘|‘ ){
30 if( isw[x+dx[i]][y+dy[i]] )
31 return 1;
32 if( step%2 ){ //奇,变
33 if( i%2 ) //奇数
34 pass = false; //不可以通过
35 else
36 pass = true; //可以通过
37 }
38 else { //不变
39 if( i%2 ) //奇数
40 pass = true; //可以通过
41 else
42 pass = false; //不可以通过
43 }
44 }
45 else if( a[x][y]==‘-‘ ){
46 if( isw[x+dx[i]][y+dy[i]] )
47 return 1;
48 if( step%2 ){ //奇,变
49 if( i%2 ) //奇数
50 pass = true; //可以通过
51 else
52 pass = false; //不可以通过
53 }
54 else{ //不变
55 if( i%2 ) //奇数
56 pass = false; //不可以通过
57 else
58 pass = true; //可以通过
59 }
60 }
61 return 0;
62 }
63 int bfs(int x,int y)
64 {
65 queue <NODE> q;
66 NODE cur,next;
67 cur.x = x;
68 cur.y = y;
69 cur.step = 0;
70 q.push(cur); //第一个节点入队
71 while(!q.empty()){
72 //队首出队
73 cur = q.front();
74 q.pop();
75 if(a[cur.x][cur.y]==‘T‘) //如果这一步已经走到了终点,则输出走到这一步的步数
76 return cur.step;
77 for(int i=0;i<4;i++){ //下一层节点入队
78 int nx = cur.x + dx[i];
79 int ny = cur.y + dy[i];
80 if( judge(nx,ny,i,cur.step) ) //判定这一步可走否
81 continue;
82 if(a[nx][ny]==‘|‘ || a[nx][ny]==‘-‘){ //如果这一步是碰到*的
83 if(pass){ //可以通过*
84 nx += dx[i];
85 ny += dy[i];
86 }
87 else{ //不可以通过*
88 nx -= dx[i];
89 ny -= dy[i];
90 }
91 }
92 next.x = nx; //可走,记录下一步的位置
93 next.y = ny;
94 next.step = cur.step + 1; //可走,步数累加
95 isw[next.x][next.y] = true; //可走,标记走过
96 q.push(next);
97 }
98 }
99 }
100 int main()
101 {
102 while(cin>>M>>N){
103 for(int i=1;i<=M;i++)
104 for(int j=1;j<=N;j++){
105 cin>>a[i][j];
106 if(a[i][j]==‘S‘){
107 startx = i;
108 starty = j;
109 }
110 }
111 memset(isw,0,sizeof(isw));
112 isw[startx][starty] = true;
113 cout<<bfs(startx,starty)<<endl;
114 }
115 return 0;
116 }
Freecode : www.cnblogs.com/yym2013