DFS
前置知识:二叉树的遍历
三种遍历
- 先根遍历(根左右)
- 中根遍历(左根右)
- 后根遍历(左右根)
注意:这里的左右为左右子树
e.g.
1. 先根遍历:271653894
1. 中根遍历:175632849
1. 后根遍历:153674982
二叉树的确定
给定先根和中根、中根和后根遍历结果,可以唯一确定二叉树
e.g. 上面,在先根中确定2为根,在中根中找到2,则2前后分别为其左右子树;再在先根中找到7,在中根中找到7,则7前后为其左右子树,以此类推。中根后根与前根后根是对称的。
给定先根和后根遍历结果,不能唯一确定二叉树
只知道根数量而不知道左右子树数量
递归
递归特征:大问题与子问题除了规模其他都一样
斐波那契数列的递归实现
1 | int fi(int a){ |
即有一个特定模板:
即先写程序出口(不需要递归的特殊情况),再写普通情况(递归)
全排列问题
输入一个正整数n,按字典序输出n-1的全排列
递归特征
- 若第一个数确定,剩余的问题就是其余n-1个数的全排列
- 若前k个数已经排好,剩余问题就是其余n-k个数的全排列
代码实现
1 |
|
若n==3:
vis:0 0 0 0 step==1
进入for循环: vis[1]==0
使num[1]=1 vis[1] = 1
num: 0 1 0 0 0
vis:0 1 0 0 表示1用过了
vis: 0 1 0 0 step==2
进入for循环: vis[2]==0
num[2]=2 vis[2] = 1
num: 0 1 2 0 0
vis:0 1 1 0 表示1,2用过了
vis:0 1 1 0 step==3
进入for循环: vis[3]==0
num[3]=3 vis[3] = 1
num: 0 1 2 3 0
vis:0 1 1 1 表示1,2,3用过了
vis:0 1 1 1 step==4
step == 3+1成立,到达边界,则输出num[1]到num[n] 123
return 到dfs(3)中(谁调用的返回谁)
dfs(3):vis[3]=0 vis:0 1 1 0 程序结束返回dfs(2)
dfs(2):vis[2]=0 vis:0 1 0 0
此时进行下一次循环 i==3,vis[3]==0
num[2]=3,vis[3]=1
num: 0 1 3 0
vis:0 1 0 1 表示1,3用过了
再进入dfs(3),重复上述操作后
num:0 1 3 2
vis:0 1 1 1
进入dfs(4)到达边界输出 132
return 到dfs(3)中重复上述过程
若没有vis[i]=0的回溯,则第一遍return后vis仍保持全标记1状态,则无法再输出其他排列直接结束
基本模型
关键在于着眼于当下如何做,下一步的做法与当前一样,只是参数不同
1 | void dfs(int step){ |
例:迷宫搜索
Tempter of the Bone
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
1
2
3
4
5
6
7
8
9
10 >4 4 5
>S.X.
>..X.
>..XD
>....
>3 4 5
>S.X.
>..X.
>...D
>0 0 0Sample Output
1
2 >NO
>YES
分析:
每个block只能走一次
恰好给定时间到达出口
剪枝条件:
若可走的block总数小于时间:全走完都开不了门,肯定NO
若起点在左上角,门在右下角,没有障碍物且最短路径(曼哈顿距离:行坐标差减列坐标差)都比时间长,肯定NO
奇偶性剪枝(应用条件:每个格子只能等一秒):
使行列坐标相加为偶数的标为0,为奇数的标为1,发现1的下一步一定为0,0的下一步一定为1
那么如果从0走到1或从1走到0,所需时间为奇数;如果从1走到1或从0走到0,所需时间为偶数
那么如果规定时间为偶数,则从0到1或从1到0肯定NO,反之亦然。
代码
1 |
|