0
点赞
收藏
分享

微信扫一扫

DFS 深度优先搜索

萨科潘 2022-03-11 阅读 46

DFS 深度优先搜索

基本概述

DFS本质上就是递归,要想学会DFS就要理解好递归。

递归就是"自己"调用"自己"的过程,但是一定要设置递归的终止条件,调用函数的过程就是将函数进行压栈执行,如果不设置终止条件,函数就会不断的调用自己,也就是一直压栈下去,最终爆栈。

重要的点有三个:

  1. 递归终止条件如何设置
  2. 返回值应该是什么,该传递给上一层什么信息
  3. 这一层的递归中应该做什么工作

经典例题

排列数字

给定一个整数 n n n,将数字 1 ∼ n 1∼n 1n 排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

思路:

在这里插入图片描述

代码:

import java.util.*;

public class Main {
    static final int N = 20;
    static int[] p = new int[N]; // 用于存放排列好的数字
    static boolean[] st = new boolean[N]; // 判断数字是否出现过的数组
    static int n;
    
    public static void dfs(int u) {
        // 当搜索层数等于树的深度时,就可以输出结果
        if (u == n) {
            for (int i = 0; i < n; i++) {
                System.out.print(p[i] + " ");
            }
            System.out.println();
            return; // 要注意回溯
        }
        // 以每个数字开头的情况有n中,根节点上就有n个分支,所以需要循环n次,每次都搜索到最深处找到答案
        for (int i = 1; i <= n; i ++) {
            if (!st[i]) {
                p[u] = i; // 将第n层的不重复数字放到数组中
                st[i] = true; // 将这个数字标记为出现过
                dfs(u + 1);
                st[i] = false; // 恢复现场,将此数字标记为未出现过
            }
        }      
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        dfs(0); // 从第0层,也就是根节点进行搜索
    }
}

n-皇后问题

n n n−皇后问题是指将 n n n 个皇后放在 n × n n×n n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

在这里插入图片描述

输入样例:

4

输出样例:

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

思路:

代码:

import java.util.*;

public class Main {
    static final int N = 20; // 将数组长度设置为20防止下标越界问题
    static int n;
    static char[][] g = new char[N][N];
    static boolean[] col = new boolean[N], dg = new boolean[N], udg = new boolean[N];
    
    public static void dfs(int row) {
        if (row == n) { // 判断是否每一行都填上了棋子(是否到了树的最大深度)
            for (int i = 0 ;i < n; i++) {
                for (int j = 0; j < n ; j++) 
                    System.out.print(g[i][j]);
                System.out.println();
            }
            System.out.println();
            return; // 回溯
        }
        // 用有n列,就需要dfs处理n次
        for (int i = 0; i < n; i++) {
            if (!col[i] && !dg[n - row + i] && !udg[row + i]) { // 判断列上,两个对角线上是否出现过
                g[row][i] = 'Q'; // 填入棋子
                col[i] = dg[n - row + i] = udg[row + i] = true; // 标记为已经填入棋子
                dfs(row + 1); // 递归处理下一行
                col[i] = dg[n - row + i] = udg[row + i] = false; // 结束递归后恢复现场 
                g[row][i] = '.'; // 同上
            }
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        
        // 在dfs前需要初始化棋盘
        for (int i = 0 ;i < n; i++)
            for (int j = 0; j < n ; j++) 
                g[i][j] = '.';
        // 也可以使用Arrays.fill()方法来初始化
        // for (char[] c : g) {
        //     Arrays.fill(c, '.');
        // }
        dfs(0); // 从0开始的dfs
    }
}
举报

相关推荐

0 条评论