深度优先检索——DFS

搜索

深度优先搜索

其实之前几篇博客的递归就已经很接近dfs了。

伪代码描述

这里写图片描述
我们先回顾一下之前已经介绍过的广度优先搜索——BFS
广度优先搜索就是在由状态的转移和扩展构成的解答树上层次遍历的结果
与其相对的,假如我们改变对解答树的遍历方式,改为优先遍历层次更深的状态,
直到遇到一个状态节点,其不再拥有子树,则返回上一层,访问其未被访问过的子树,
直到解答树中所有的状态都被遍历完毕。
在搜索过程中为了达到这一目的,我们立即扩展新得到的状态,而更早得到的状态更迟的得到扩展,为了达到这种效果我们按理说需要使用堆栈保存和扩展搜索过程得到的状态,但是这种扩展状态可以通过递归天然实现,所以我们这里不使用堆栈而是用递归程序。使用栈的下一篇博客写。
由于少了BFS中按层次顺序遍历的特性,所以当DFS搜索到我们需要的状态时,其不再有某种最优的特性,因此当使用深度优先搜索搜索,我们更多是求解有或没有的问题,即对解答树是否有我们需要的答案进行判定,而一般不使用深度优先检索求解最优解问题。

Temple of the bone

单输入输出版
题目描述:
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.
输入:
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.
输出:
For each test case, print in one line “YES” if the doggie can survive, or “NO” otherwise.
样例输入:

4 4 5
S.X.
..X.
..XD
....

….

3 4 5
S.X.
..X.
...D
0 0 0

样例输出:
NO

YES
题目大意:有一个N*M的迷宫,包括起点S,终点D,墙X和地面,0秒时主人公从S出发,每秒能走到四个
与其相邻位置中的一个,且每个位置被行走之后就不能再次走入,问是否存在这样一条路径使主人公在T秒
时刚好走到D。
分析:
这个问题中,题面不再要求我们求最优解,而是转而需要我们判定是否存在一条符合条件的路径,所以使用
深度优先搜索来达到这个目的。
确定状态三元组(x,y,t),(x,y)为当前坐标,t为从起点走到该点所需要的时间。我们所需要的状态(dx,dy,T),其中(dx,dy)为D所在点的坐标,T为所需的时间。初始状态为(sx,sy,0),其中(sx,sy)为S点的坐标。
剪枝
主人公每走一步,坐标量中只有一个量发生加一或减一变化,那么两个坐标分量之和奇偶性将发生变化。
主人公走奇数步,当前坐标位置分量之和奇偶性必与原位置不同
主人公走偶数步,当前坐标位置分量之和奇偶性必与原位置相同
那么我们需要减去的情况就是是
若起点坐标和奇偶性和终点不同,但走了偶数步的情况
若起点坐标和奇偶性和终点相同,但走了奇数步的情况
直接跳过搜索状态,输出”NO”

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Temple_of_the_bone {
    static boolean success=false;
    static char maze[][] =new char[8][8];
    static int go[][]={{0,1},{1,0},{0,-1},{-1,0},};
    public static void main(String[] args) throws IOException {
        //Scanner 录入有点问题,所以用BuffereDReader
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        String str[]=bf.readLine().split(" ");
        int n=Integer.parseInt(str[0]);//行数
        int m=Integer.parseInt(str[1]);//列数
        int t=Integer.parseInt(str[2]);//列数
        for (int i = 0; i < n; i++) {
            String temp=bf.readLine();
            maze[i]=temp.toCharArray();
        }
        for (int i = 0; i < n; i++) {
        //剪枝,先遍历地图找到D点坐标(sx,sy) 
        //判断条件若改成(maze[i][j]=='S'&&(i+j)%2==((sx+sy)%2+t%2)%2)
        //判断SD的奇偶性关系,符合就搜索,不符合就跳过
            for (int j = 0; j < m; j++) {
                if (maze[i][j]=='S') {//开始位置
                    maze[i][j]='X';//访问过的不可被访问,置为墙
                    dfs(i,j,0,n,m,t);
                }
            }
        }
        System.out.println(success?"YES":"NO");

    }
    //其实只需要使用前三个参数 含义分别是 坐标(x,y)还有走路时间t   后面三个参数相当于常量,分析题的时候直接忽略,不要被影响
    public static void dfs(int x, int y, int time, int n, int m,int t) {
        for (int i = 0; i < go.length; i++) {
            int nx=x+go[i][0];
            int ny=y+go[i][1];
            if (nx<0||nx>=n||ny<0||ny>=m) {//超出地图边界 跳过
                continue;
            }
            if (maze[nx][ny]=='X') {//遇到墙跳过
                continue;
            }
            if (maze[nx][ny]=='D') {//正好为门
                if (time+1==t) {
                    success=true;
                    return ;
                }else {
                    continue;
                }
            }
            maze[nx][ny]='X';//访问过的不可被访问,置为墙
            dfs(nx, ny, time+1, n, m, t);
            maze[nx][ny]='.';//未找到则回溯
            if (success) {
                return ;
            }
        }
    }

}

总结
dfs搜地图的时候

  1. 录入地图信息,静态成员变量
  2. 从头位置遍历(将已经使用的位置置为不可用)
  3. 递归dfs(… , 初始状态)
  4. dfs函数设计,先把变换后的下标存起来
    判断下标合法性 不合法跳过
    判断是否为不可达位置(已经到达过一次不允许重复的也视为不可达) 不可达跳过
    找到目标状态,操作,返回。
  5. 主函数写dfs的位置,如果搜索不到我们需要的状态
    将当前位置回溯到上一步,也就是这一步不可被选取,将原来设置为已访问(不可达)的标记改为常规状态(可访问,被选取)
  6. 返回最终结果

    与广度优先搜索的比较
    分析搜索问题的三要素:
    搜索空间:
    和广度优先搜索一样,搜索空间仍然是所有状态
    搜索目的:
    DFS——查找一个可以表示原问题解的状态
    BFS——查找一个可以表示原问题的最优解
    搜索方法:
    DFS—— 在解答树上先序遍历
    BFS——在解答树上层次遍历

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值