文章目录

  • 前言
  • 一、DFS算法大致思路
  • 二、一个示例问题
  • 1.问题表述
  • 2.实现代码



前言

遍历一个树或者图的过程中,DFS(深度优先搜索)是比较常用的一个算法。这次记录一下DFS算法的大致思路和一个示例。


一、DFS算法大致思路

DFS算法(深度优先算法)最重要的是搜索次序。对于一个全排列问题来说,以n=3为例,他的搜索顺序是这样的:

Java中DFS是什么 java dfs算法_Java中DFS是什么


假设最开始有3个空位,从前往后填数字,每次填一个数字,填的数字不能和之前的一样。

最开始的时候,三个位置都为空,即_ _ _

首先填写第一个空位,第一个空位可以填 1,填写后为:1 __ __

填好第一个空位,填第二个空位,第二个空位可以填 2,填写后为:1 2 __

填好第二个空位,填第三个空位,第三个空位可以填 3,填写后为: 1 2 3

这时候,空位填完,无法继续填数,所以这是一种方案,输出。

然后往后退一步,退到了状态:1 2 __ 。剩余第三个空位没有填数。第三个空位上除了填过的 3 ,没有其他数字可以填。

因此再往后退一步,退到了状态:1 __ __。第二个空位上除了填过的 2,还可以填 3。第二个空位上填写 3,填写后为:1 3 __

填好第二个空位,填第三个空位,第三个空位可以填 2,填写后为: 1 3 2

这时候,空位填完,无法继续填数,所以这是一种方案,输出。

然后往后退一步,退到了状态:1 3 __ 。剩余第三个空位没有填数。第三个空位上除了填过的 2,没有其他数字可以填。

因此再往后退一步,退到了状态:1 __ __。第二个空位上除了填过的 2,3,没有其他数字可以填。

因此再往后退一步,退到了状态:__ __ __。第一个空位上除了填过的 1,还可以填 2或者3.剩下的过程与此类似。

二、一个示例问题

1.问题表述

这里利用了一个比较经典的“N-皇后”问题:n− 皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。现在给定整数 n,请你输出所有的满足条件的棋子摆法。

输出格式:每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。

其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。

每个方案输出完成后,输出一个空行。

2.实现代码

import java.io.*;

class Main {
    
    // bool数组用来判断搜索的下一个位置是否可行
    // col列,dg对角线,udg反对角线
    // g[N][N]用来存路径
    public static int N = 20;
    public static char[][] g = new char[N][N];
    public static boolean[] col = new boolean[N], dg = new boolean[N], udg = new boolean[N];
    public static int n;
    
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(bufferedReader.readLine());
        
        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < n; j ++) {
                g[i][j] = '.';
            }
        }
        
        dfs(0);
        bufferedReader.close();
    }
    
    public static void dfs(int u) {
        if (u == 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;
        }
        
        for (int i = 0; i < n; i ++) {
            // 剪枝(对于不满足要求的点,不再继续往下搜索)  
            // udg[n - u + i],+n是为了保证下标非负
            if (!col[i] && !dg[u + i] && !udg[n - u + i]) {
                g[u][i] = 'Q';
                col[i] = dg[u + i] = udg[n - u + i] = true;
                dfs(u + 1);
                // 恢复现场 
                col[i] = dg[u + i] = udg[n - u + i] = false;
                g[u][i] = '.';
            }
        }
    }
}

利用DFS按行枚举

对角线 dg[u+i],反对角线udg[n−u+i]中的下标 u+i和 n−u+i 表示的是截距

核心目的:找一些合法的下标来表示dg或udg是否被标记过