HDU 1010 Tempter of the Bone【DFS经典题+奇偶剪枝详解】
Tempter of the Bone
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 125945 Accepted Submission(s): 33969
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.
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0
这道题可以不剪枝操作,也不会T了!
不懂剪枝的看这里:DFS中的奇偶剪枝学习笔记
这里说下不剪枝的技巧:为了避免多余的边界控制,可以从i=1,j=1开始读迷宫,在读之前将迷宫初始化为全部'X',即都为墙。这样在迷宫读取完毕后,周围就会自动出现一圈'X',这样就可以在搜索的时候只判断遇到'X'就return了。
这里贴一下深搜代码,不管剪不剪枝,这一段是可以不用修改的。
1 inline int DFS(int x,int y,int T) 2 { 3 if(mp[x][y]!='.'&&mp[x][y]!='S')//碰到X即为边界返回 4 return 0; 5 if(T==1)//剩一步时即可判断是否为出口,找到返回1 6 { 7 if(mp[x-1][y]=='D') 8 return 1; 9 if(mp[x+1][y]=='D') 10 return 1; 11 if(mp[x][y-1]=='D') 12 return 1; 13 if(mp[x][y+1]=='D') 14 return 1; 15 return 0; 16 } 17 else 18 { 19 mp[x][y]='X';//标记走过 20 if(mp[x-1][y]=='.'&&DFS(x-1,y,T-1)) 21 return 1; 22 if(mp[x+1][y]=='.'&&DFS(x+1,y,T-1)) 23 return 1; 24 if(mp[x][y-1]=='.'&&DFS(x,y-1,T-1)) 25 return 1; 26 if(mp[x][y+1]=='.'&&DFS(x,y+1,T-1)) 27 return 1; 28 mp[x][y]='.';//还原走过 29 return 0; 30 } 31 return 0; 32 }
关于奇偶剪枝
首先举个例子,有如下4*4的迷宫,'.'为可走路段,'X'为障碍不可通过
S...
....
....
...D
从S到D的最短距离为两点横坐标差的绝对值+两点纵坐标差的绝对值 = abs(Sx - Dx) + abs(Sy - Dy) = 6,这个应该是显而易见的。
遇到有障碍的时候呢
S.XX
X.XX
...X
...D
你会发现不管你怎么绕路,最后从S到达D的距离都是最短距离+一个偶数,这个是可以证明的
而我们知道:
奇数 + 偶数 = 奇数
偶数 + 偶数 = 偶数
因此不管有多少障碍,不管绕多少路,只要能到达目的地,走过的距离必然是跟最短距离的奇偶性是一致的。
所以如果我们知道从S到D的最短距离为奇数,那么当且仅当给定的步数T为奇数时,才有可能走到。如果给定的T的奇偶性与最短距离的奇偶性不一致,那么我们就可以直接判定这条路线永远不可达了。
这里还有个小技巧,我们可以使用按位与运算来简化奇偶性的判断。我们知道1的二进制是1,而奇数的二进制最后一位一定是1,而偶数的二进制最后一位一定是0。所以如果数字&1的结果为1,那么数字为奇数,反之为偶数。
下面给出奇偶剪枝后的main函数代码:
1 int main() 2 { 3 int sx,sy,dx,dy; 4 int N,M,T; 5 while(scanf("%d%d%d",&N,&M,&T)&&N&&M&&T) 6 { 7 getchar(); 8 memset(mp,'X',sizeof(mp));//把周围边界全部变成X 9 for(int i=1;i<=N;i++)//从1开始读,留出边界位置 10 { 11 for(int j=1;j<=M;j++) 12 { 13 scanf("%c",&mp[i][j]); 14 if(mp[i][j]=='S') 15 { 16 sx=i; 17 sy=j; 18 } 19 else if(mp[i][j]=='D') 20 { 21 dx=i; 22 dy=j; 23 } 24 } 25 getchar(); 26 } 27 if((abs(sx-dx)+abs(sy-dy)-T)&1)//奇偶剪枝,对1用按位与运算求奇偶 28 printf("NO\n"); 29 else if(DFS(sx,sy,T)==1) 30 printf("YES\n"); 31 else printf("NO\n"); 32 } 33 return 0; 34 }
所以完整的AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 char mp[15][15]; 4 inline int DFS(int x,int y,int T) 5 { 6 if(mp[x][y]!='.'&&mp[x][y]!='S')//碰到X即为边界返回 7 return 0; 8 if(T==1)//剩一步时即可判断是否为出口,找到返回1 9 { 10 if(mp[x-1][y]=='D') 11 return 1; 12 if(mp[x+1][y]=='D') 13 return 1; 14 if(mp[x][y-1]=='D') 15 return 1; 16 if(mp[x][y+1]=='D') 17 return 1; 18 return 0; 19 } 20 else 21 { 22 mp[x][y]='X';//标记走过 23 if(mp[x-1][y]=='.'&&DFS(x-1,y,T-1)) 24 return 1; 25 if(mp[x+1][y]=='.'&&DFS(x+1,y,T-1)) 26 return 1; 27 if(mp[x][y-1]=='.'&&DFS(x,y-1,T-1)) 28 return 1; 29 if(mp[x][y+1]=='.'&&DFS(x,y+1,T-1)) 30 return 1; 31 mp[x][y]='.';//还原走过 32 return 0; 33 } 34 return 0; 35 } 36 int main() 37 { 38 int sx,sy,dx,dy; 39 int N,M,T; 40 while(scanf("%d%d%d",&N,&M,&T)&&N&&M&&T) 41 { 42 getchar(); 43 memset(mp,'X',sizeof(mp));//把周围边界全部变成X 44 for(int i=1;i<=N;i++)//从1开始读,留出边界位置 45 { 46 for(int j=1;j<=M;j++) 47 { 48 scanf("%c",&mp[i][j]); 49 if(mp[i][j]=='S') 50 { 51 sx=i; 52 sy=j; 53 } 54 else if(mp[i][j]=='D') 55 { 56 dx=i; 57 dy=j; 58 } 59 } 60 getchar(); 61 } 62 if((abs(sx-dx)+abs(sy-dy)-T)&1)//奇偶剪枝,对1用按位与运算求奇偶 63 printf("NO\n"); 64 else if(DFS(sx,sy,T)==1) 65 printf("YES\n"); 66 else printf("NO\n"); 67 } 68 return 0; 69 }
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。