【算法基础】3.1 DFS和BFS

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。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei *

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值