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
Problem Description
The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze. 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.
Input
The input consists of multiple test cases. The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively. The next N lines give the maze layout, with each line containing M characters. A character is one of the following: '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.
Output
For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise.
Sample Input
4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0
Sample Output
NO
YES
Author
ZHANG, Zheng
Source
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1010
题意:一个n*m的矩阵,老鼠的起点在矩阵中的'S'上,终点在矩阵中的'D',其中'X'是墙,老鼠不能通过,'.'是路但是只能通过一次,过了一次之后就不能再走这个地方了,终点D在第K秒是打开,这就要求老鼠能够在第K秒是正好到达D点,如果不能就输出NO,可以的话就输出YES.
这道题可以不剪枝操作,也不会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("NOn");
29 else if(DFS(sx,sy,T)==1)
30 printf("YESn");
31 else printf("NOn");
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("NOn");
64 else if(DFS(sx,sy,T)==1)
65 printf("YESn");
66 else printf("NOn");
67 }
68 return 0;
69 }
- wait方法和sleep方法的区别
- Java面试系列10
- python django整理(三)页面基础(仿BBS)
- 高并发场景下的httpClient优化使用
- socket.io 相关:Example: A simple chat server(官方 实例)
- django整理(四)配置setting文件(CSS,JS,images,templates)路径
- idea 远程调试 tomcat web应用
- Java 中冷门的 synthetic 关键字原理解读
- Spring 数据库连接(Connection)绑定线程(Thread)的实现
- Golang语言实现AzDG可逆加密算法实例
- python django整理(五)配置favicon.ico,解决警告Not Found: /favicon.ico
- SpringMVC + Mybatis bug调试 SQL正确,查数据库却返回NULL
- 原生javascript实现图片轮播效果代码
- Spring AOP中 args和arg-names的区别
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- docker里运行docker命令
- 一次性实战java8 新特性(全)—— Lambda、Optional、stream、DateTime
- 面试Python高频问题汇总
- python自学成才之路 miniconda创建虚拟环境
- 逐行阅读Spring5.X源码(一) BeanDefinition,起点
- linux 磁盘占满 查看占用
- 逐行阅读Spring5.X源码(二) BeanDefinition的父接口-AttributeAccessor 、BeanMetadataElement ,进阶
- 64. Vue中的插槽slot
- 65. Vue中的作用域插槽
- SpringBoot : 全局异常配置
- springboot事务管理
- Java : 分享一个通用的获取请求客户端IP的方法
- 一套常用的css初始化样式
- Octave 笔记
- VSCode如何设置Vue前端的debug调试