文章目录
- 前言
- 一、DFS算法大致思路
- 二、一个示例问题
- 1.问题表述
- 2.实现代码
前言
遍历一个树或者图的过程中,DFS(深度优先搜索)是比较常用的一个算法。这次记录一下DFS算法的大致思路和一个示例。
一、DFS算法大致思路
DFS算法(深度优先算法)最重要的是搜索次序。对于一个全排列问题来说,以n=3为例,他的搜索顺序是这样的:
假设最开始有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是否被标记过