DFS
https://oi-wiki.org/graph/dfs/
DFS 全称是 Depth First Search,中文名是深度优先搜索,是一种用于遍历或搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点走。
该算法讲解时常常与 BFS 并列,但两者除了都能遍历图的连通块以外,用途完全不同,很少有能混用两种算法的情况。
DFS 常常用来指代用递归函数实现的搜索,但实际上两者并不一样。有关该类搜索思想请参阅 .DFS(搜索)
例题列表
一些相关题目可见:【算法总结】——排列型回溯
842. 排列数字
https://www.acwing.com/problem/content/844/
import java.util.Scanner;
public class Main {
static int[] a = new int[7];
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
boolean[] used = new boolean[n];
dfs(0, n, used);
}
// 每次填第 i 位
public static void dfs(int i, int n, boolean[] used) {
if (i == n) {
for (int j = 0; j < n; ++j) System.out.print(a[j] + " ");;
System.out.println();
return;
}
for (int j = 0; j < n; ++j) {
if (!used[j]) {
used[j] = true;
a[i] = j + 1;
dfs(i + 1, n, used);
used[j] = false;
}
}
}
}
843. n-皇后问题
https://www.acwing.com/problem/content/845/
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main {
static char[][] board;
static int n;
static Set<Integer> s1 = new HashSet<>(), s2 = new HashSet<>(), s3 = new HashSet<>();
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
board = new char[n][n];
for (int i = 0; i < n; ++i) Arrays.fill(board[i], '.');
dfs(0);
}
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(board[i][j]);
System.out.println();
}
System.out.println();
return;
}
for (int col = 0; col < n; ++col) {
if (!s1.contains(col) && !s2.contains(row + col) && !s3.contains(row - col)) {
s1.add(col);
s2.add(row + col);
s3.add(row - col);
board[row][col] = 'Q';
dfs(row + 1);
s1.remove(col);
s2.remove(row + col);
s3.remove(row - col);
board[row][col] = '.';
}
}
}
}
BFS
https://oi-wiki.org/graph/bfs/
BFS 全称是 Breadth First Search,中文名是宽度优先搜索,也叫广度优先搜索。
是图上最基础、最重要的搜索算法之一。
所谓宽度优先。就是每次都尝试访问同一层的节点。 如果同一层都访问完了,再访问下一层。
这样做的结果是,BFS 算法找到的路径是从起点开始的 最短 合法路径。换言之,这条路径所包含的边数最小。
在 BFS 结束时,每个节点都是通过从起点到该点的最短路径访问的。
算法过程可以看做是图上火苗传播的过程:最开始只有起点着火了,在每一时刻,有火的节点都向它相邻的所有节点传播火苗。
例题列表
844. 走迷宫
https://www.acwing.com/problem/content/846/
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(), m = scanner.nextInt();
int[][] b = new int[n][m];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) b[i][j] = scanner.nextInt();
}
int[] dx = {-1, 0, 1, 0}, dy = {0, -1, 0, 1};
int step = 0;
Queue<int[]> q = new LinkedList<>();
q.offer(new int[]{0, 0});
b[0][0] = 1;
while (!q.isEmpty()) {
int sz = q.size();
for (int i = 0; i < sz; ++i) {
int[] cur = q.poll();
assert cur != null;
int x = cur[0], y = cur[1];
if (x == n - 1 && y == m - 1) {
System.out.println(step);
return;
}
for (int k = 0; k < 4; ++k) {
int nx = x + dx[k], ny = y + dy[k];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && b[nx][ny] == 0) {
q.offer(new int[]{nx, ny});
b[nx][ny] = 1;
}
}
}
step++;
}
}
}
845. 八数码⭐⭐⭐⭐⭐(矩阵的一维表示 + bfs)
https://www.acwing.com/activity/content/problem/content/908/
将矩阵的形式表示成一个字符串 12345678x
,这样方便存储状态以及找到字符x所在的位置。
一维数组的下标 k 对应的二维数组的下标为 : [k / 3, k % 3]
每次找到 x 的位置,然后让它尝试向 4 个方向移动,直到找到最终状态。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
StringBuilder s = new StringBuilder();
for (int i = 0; i < 9; ++i) s.append(scanner.next().charAt(0));
System.out.println(bfs(s));
}
static int bfs(StringBuilder s) {
String endS = "12345678x";
int[] dx = {-1, 0, 1, 0}, dy = {0, -1, 0, 1};
Queue<StringBuilder> q = new LinkedList<>(); // 使用StringBuilder是因为方便交换两个字符的位置
Map<String, Integer> d = new HashMap<>(); // 使用String作为哈希表的key
d.put(s.toString(), 0);
q.offer(s);
while (!q.isEmpty()) {
StringBuilder t = q.poll();
String ts = t.toString();
if (endS.equals(ts)) return d.get(ts); // 找到了答案
// 找到 x 所在的位置,让 x 尝试向 4 个方向移动
int distance = d.get(ts), k = ts.indexOf('x'), x = k / 3, y = k % 3;
for (int i = 0; i < 4; ++i) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < 3 && b >= 0 && b < 3) {
swap(t, a * 3 + b, k);
String nextTs = t.toString();
if (d.get(nextTs) == null) {
d.put(nextTs, distance + 1);
q.offer(new StringBuilder(t));
}
swap(t, a * 3 + b, k);
}
}
}
return -1;
}
static void swap(StringBuilder a, int i, int j) {
char t = a.charAt(i);
a.setCharAt(i, a.charAt(j));
a.setCharAt(j, t);;
}
}
这道题使用了 String 和 StringBuilder。