Tempter of the Bone
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 57248 Accepted Submission(s): 15482
The maze was a rectangle with sizes N by M. There was a door in the maze. At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second). Therefore the doggie had to arrive at the door on exactly the T-th second. In every second, he could move one block to one of the upper, lower, left and right neighboring blocks. Once he entered a block, the ground of this block would start to sink and disappear in the next second. He could not stay at one block for more than one second, nor could he move into a visited block. Can the poor doggie survive? Please help him.
'X': a block of wall, which the doggie cannot enter;
'S': the start point of the doggie;
'D': the Door; or
'.': an empty block.
The input is terminated with three 0's. This test case is not to be processed.
1 //Tempter of the Bone 2 #include<iostream> 3 #include<cmath> 4 #define MAX 10 5 using namespace std; 6 7 int N,M,T,ei,ej; 8 bool visited[MAX][MAX],found; 9 char maze[MAX][MAX]; 10 11 void DFS(int i, int j, int t) 12 { 13 if(found||t>T)return; 14 if(i<0||i>=N||j<0||j>=M)return; 15 if(maze[i][j]=='D' && T==t){found=true;return;} 16 17 int temp=abs(i-ei)+abs(j-ej); 18 temp=T-temp-t; 19 if(temp&1) return ;//奇偶剪枝 20 21 if(maze[i-1][j]!='X' && !visited[i-1][j]) 22 { 23 visited[i-1][j]=true; 24 DFS(i-1,j,t+1); 25 visited[i-1][j]=false; 26 } 27 if(maze[i+1][j]!='X' && !visited[i+1][j]) 28 { 29 visited[i+1][j]=true; 30 DFS(i+1,j,t+1); 31 visited[i+1][j]=false; 32 } 33 if(maze[i][j-1]!='X' && !visited[i][j-1]) 34 { 35 visited[i][j-1]=true; 36 DFS(i,j-1,t+1); 37 visited[i][j-1]=false; 38 } 39 if(maze[i][j+1]!='X' && !visited[i][j+1]) 40 { 41 visited[i][j+1]=true; 42 DFS(i,j+1,t+1); 43 visited[i][j+1]=false; 44 } 45 } 46 47 int main() 48 { 49 int blcNum,i,j,si,sj; 50 while(cin>>N>>M>>T,N||M||T) 51 { 52 memset(visited,false,sizeof(visited)); 53 blcNum = 0; 54 for(i=0;i<N;i++) 55 for(j=0;j<M;j++) 56 { 57 cin>>maze[i][j]; 58 if(maze[i][j]=='S'){si=i;sj=j;visited[i][j]=true;} 59 if(maze[i][j]=='D'){ei=i;ej=j;} 60 if(maze[i][j]=='X')blcNum++; 61 } 62 found=false; 63 if(N*M-blcNum-1>=T)DFS(si,sj,0); 64 if(found)cout<<"YES"<<endl; 65 else cout<<"NO"<<endl; 66 } 67 system("pause"); 68 return 0; 69 }
这个是从网上参考来的,其实我只是会一些简单的深搜,这样的我还得看别人的代码才能写的出来。而且这里面我还不懂什么是奇偶剪枝,还是练的太少!
下面给出奇偶剪枝的定义:
什么是奇偶剪枝?
把矩阵看成如下形式:
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
从为 0 的格子走一步,必然走向为 1 的格子 。
从为 1 的格子走一步,必然走向为 0 的格子 。
即:
从 0 走向 1 必然是奇数步,从 0 走向 0 必然是偶数步。
所以当遇到从 0 走向 0 但是要求时间是奇数的或者 从 1 走向 0 但是要求时间是偶数的,都可以直接判断不可达!
比如有一地图:
- S...
- ....
- ....
- ....
- ...D
要求从S点到达D点,此时,从S到D的最短距离为s = abs ( dx - sx ) + abs ( dy - sy )。
如果地图中出现了不能经过的障碍物:
- S..X
- XX.X
- ...X
- .XXX
- ...D
此时的最短距离s' = s + 4,为了绕开障碍,不管偏移几个点,偏移的距离都是最短距离s加上一个偶数距离。
就如同上面说的矩阵,要求你从0走到0,无论你怎么绕,永远都是最短距离(偶数步)加上某个偶数步;要求你从1走到0,永远只能是最短距离(奇数步)加上某个偶数步。
百度百科里的定义:http://baike.baidu.com/link?url=uYxdzAqK0DNMNsTOruGv79VoqbTiJiGFyTNyMwM5X4Xf_gpDmRH0oVcTRb1qlXN_kKlkQ0CwncSpI87O9yO4cK
奇偶剪枝的证明:http://blog.csdn.net/code_pang/article/details/8839432
问题描述
在一个n行m列的迷宫中,每一步只能向上、下、左、右中任意方向走一格,迷宫中有围墙的地方是无法到达的。从起点s开始,能否刚好走t步,到达e。
例如在下面5行5列的迷宫中,能否恰好经过9步,从s走到e。初始位置在s上,#是围墙。
奇偶剪枝
设起点s的坐标为(sx,sy),终点e的坐标为(ex,ey);
对s的一次操作为对sx或sy进行+1或-1;
若经过t次操作后,s的坐标刚好等于e,则说从s经过t步可以到达e。
在理想情况下,s到e需要的最小步数为m
m=|ex-sx|+|ey-sy|
若t<m,肯定是无法到达的。
当t>=m时,从s到e的行走路径由两部分组成,
一部分为需要走的最少步数m;
另一部分是为了使得刚好行走t步到达e,所需要走的附加步数a,a=t-m;
这a步即为:从需要走m步的最短路径上走出去,再回到最短路径上所走的步数。
假设走出去这段路径长度为b,那回来时的路径长度一定也是b,因此,附加步数的路径长度a等于2b步。
因为走出去时,对坐标进行了b次+1或-1的操作,为使坐标再恢复到最短路径上,就需要进行b次-1或+1的操作,并且与走出去时是相反的。注意:走出去和拐回来的过程中可能参杂着最短路径上的操作,所以b是除去这些参杂操作后的步数。
如下图所示:
从s到e的黑色路径为一条最短路径,红色和蓝色路线组成的路径,为走出最短路径的路径。其中蓝色箭头是参杂着的最短路径中的操作,只有红色箭头才是走出去和拐回来的路径,如果将红色路径去掉,从s向右走,经过绿色箭头到达e,这也是一条最短路径。
因为a=2b,是个偶数,又因为a=t-m,所以当t和m的奇偶性相同时,a才能是偶数。也就是说,当t和m的奇偶性相同时,才有可能从s经过t步,到达e。
所以,当最小步数m与t同为奇数,或同为偶数时,才有可能从s经过t步,到达e。
我的观点:从直观上理解,若从最短路走出去,然后再回来,所需的步数z肯定不是固定的奇数或偶数,但是在这z步中肯定也包含了在最短路t上所要走的步数t',所以,我们讲这奇偶剪枝里所判断的a是z减去t'之后的奇偶性,毫无疑问a肯定是偶数,所以可以直接拿来当定理用。