跳转至

DFS

前置知识

递归

目标

深度优先搜索模板题,尝试理解“状态”这个概念。

What

● 搜索,又称状态空间搜索,是指通过搜索从初始状态到目标状态的路径以完成问题求解的算法。

● depth first search(dfs), 按照深度优先的顺序对“问题状态空间”进行搜索的算法(理解理解搜索树,是不是深度优先?)。

● “深搜”,是一种包括遍历形式、状态记录与检索、剪枝优化等算法整体设计的统称。提前学习建图方法后,掌握在图上进行遍历,进一步把“问题空间”类比为一张图。

● 研究dfs算法之前,要定义该过程产生的 “搜索树” 结构,整个深搜算法就是基于该搜索树完成的(用递归实现的指数型枚举、排列性枚举、组合型枚举,其实就是深搜的三种最简单的形式)。

● dfs,常常指利用递归函数实现暴力枚举的算法。

● 递归搜索,该类搜索算法的特点在于,将要搜索的目标分成若干“层”,每层基于前几层的状态进行决策,直到达到目标状态。

How

img

八皇后问题

img

上图是,四皇后,递归搜索树,示例

// n皇后代码模板
// 按行枚举

//(1)反对角线 y=x+b, 截距 b=y−x,因为我们要把 b 当做数组下标,所以 b 不能是负的
// 所以我们 +n,保证是结果是正的
//(2)而对角线 y=−x+b, 截距是 b=y+x,这里截距一定是正的,所以不需要加偏移量

// 反对角线,左上到右下
// 对角线,左下到右上

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

#include <iostream>
using namespace std;
const int N = 20;

// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线
// g[N][N]用来存路径

int n;
char g[N][N];
bool col[N], dg[N], udg[N];

void dfs(int u)
{
    // u == n 表示已经搜了n行,故输出这条路径
    if (u == n)
    {
        for (int i = 0; i < n; i ++ ) puts(g[i]);   // 等价于cout << g[i] << endl;
        puts("");  // 换行
        return;
    }

    //对n个位置按行搜索
    for (int i = 0; i < n; i ++ )
        //剪枝(对于不满足要求的点,不再继续往下搜索)
        //udg[n - u + i],+n是为了保证大于0
        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] = '.';
        }
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            g[i][j] = '.';

    dfs(0);

    return 0;
}

image-20241014132437438

代码框架

void dfs(int u){
    // 问题的边界

    // 求解子问题

}

题单

【例5.2】组合的输出

【例5.3】自然数的拆分

LETTERS

八皇后问题

八皇后

迷宫

红与黑

棋盘问题

马走日

单词接龙

分成互质组

总结

DFS 是一个非常重要的基础算法,虽然基础,但可以用到最后的算法。

其难度,随着题面逻辑的复杂而提升,抽象的问题定义,将会成为难点。

俗话说的好,“暴力拿省一”,甚至,暴力拿金牌。虽然都是暴力,但是人家的暴力,可是高级的暴力。

一个题目,人家说,暴力,可能你连题目说的是什么,都无法有效的阅读理解。

在普及组阶段,应该不贪多,学到了 DFS,就做一个阵地战,把 DFS 打死打穿,就不往后面走了。直接去参加比赛,也依然没有大问题,甚至表现还要优于贪多的选手。

打磨技能的这个过程中,我们将获得基础能力的积累和提升,为后续算法的有效推进,做好准备。

参考

《信息学奥林匹克辞典》

acwing.com