AcWing 842. 排列数字(dfs分析本质)

本文解析了深度优先搜索(DFS)在解决全排列问题中的应用,通过实例演示了如何使用DFS遍历所有可能的方案,并探讨了其搜索策略。通过栈的数据结构,DFS展示了一种执着的搜索方式直到找到所有路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

dfs和bfs都可以对整个空间进行搜索,搜索结构如同一棵树。

但是两者搜索顺序不一样

dfs是尽可能往深处搜,当搜索到叶子结点就会回溯,之后搜下一个分支搜到尽头后又进行回溯循环往复,最终回归起点

在这里插入图片描述

“dfs是个执着的人,不论往哪条分支走,一定会走到尽头,不走到尽头是不会回来的,一旦走到尽头,回去的时候是边回溯边判断是否还有下一条分支能够继续往前走,只有确定当前点所有的路都走不通的时候才会回退一步。”

从使用的数据结构来看,dfs使用的是 ,从使用的空间来看,dfs往下搜索的时候,我们只需记录某一条路径上的所有点即可,因此它的空间是和搜索树的高度成正比的。

例题:
在这里插入图片描述
在这里插入图片描述
如何用 dfs 解决全排列问题?

dfs 最重要的是搜索顺序。用什么顺序遍历所有方案。

对于全排列问题,以 n = 3 为例,可以这样进行搜索:
55289_0cd4222d73-深度优先遍历.png

QQ截图20220302101008.png

QQ截图20220302101120.png

QQ截图20220302101157.png

QQ截图20220302101236.png

QQ截图20220302101329.png

QQ截图20220302101401.png

QQ截图20220302101430.png
DFS

#include<iostream>
#define cin std::ios::sync_with_stdio(false); cin.tie(0); cin
using namespace std;
const int N = 8;
int path[N];
bool vis[N];
int n;
void dfs(int u)
{
    if(u==n) 
    {
        for(int i=0;i<n;++i) cout<<path[i]<<' ';
        cout<<endl;
        return;
    }
    for(int i=1;i<=n;++i)
    {
        if(!vis[i])
        {
            path[u]=i;
            vis[i]=true;
            dfs(u+1);
            vis[i]=false;
        }
    }
        
}
int main()
{
    cin>>n;
    dfs(0);
    return 0;
}
//测试代码感受深搜的过程:
#include<iostream>
using namespace std;
#define debug(a) cout<<#a<<" = "<<a<<endl;
int n;
const int N = 10;
int path[N];
bool st[N];
void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
            cout<<path[i]<<' ';
        cout<<endl;
        cout<<endl;
        return ;
    } 
    for(int j=1;j<=n;j++)
    {
        cout<<"j "<<j<<" st["<<j<<"] "<<st[j]<<endl;

        if(!st[j])
        {
            st[j]=true;
            debug(j);

            path[u]=j;
            dfs(u+1);
            //把深搜想象成一个鸡思维的人,只有上方递归走到不能走后才会进行下方回溯!
            st[j]=false;
            cout<<"回溯 ";
            debug(j);
            cout<<"回溯 ";
            cout<<" st["<<j<<"] "<<st[j]<<endl;
        }
    }
}
int main()
{
    cin.tie(0),ios::sync_with_stdio(false);
    cin>>n;
    dfs(0);
    return 0;
}
//感受一下输入5时的输出:
j 1 st[1] 0 //当st[j]为0则将j加入当前搜索路径
j = 1
j 1 st[1] 1
j 2 st[2] 0 
j = 2 //因为st[2]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3 //因为st[3]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4 //因为st[4]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5 //因为st[5]=0,因此加入方案
1 2 3 4 5 //每搜索完一个方案接下来则开始回溯

回溯 j = 5
回溯  st[5] 0
回溯 j = 4
回溯  st[4] 0
j 5 st[5] 0 //由于上方j回溯到了4,结束了j=4时的循环,进入到枚举j=5时的循环
j = 5 //st[5]=0,将5纳入当前方案,并进入下一层递归,下面的是在下一层递归中枚举1,2,3,4,5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0 
j = 4 //将4纳入当前方案
1 2 3 5 4 //层数已超,输出方案

回溯 j = 4
回溯  st[4] 0 //回溯到4,下面for进入j=5
j 5 st[5] 1 //st[5]=1,则不可取
回溯 j = 5 //继续回溯
回溯  st[5] 0
回溯 j = 3 //回溯到3,下面for进入j=4
回溯  st[3] 0 
j 4 st[4] 0 
j = 4 //因为st[4]=0,因此加入方案,下面进入下一层递归,并枚举1,2,3,4,5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3 //因为st[3]=0,因此加入方案
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5 //因为st[5]=0,因此加入方案
1 2 4 3 5 //层数已超,输出方案

回溯 j = 5
回溯  st[5] 0
回溯 j = 3
回溯  st[3] 0
j 4 st[4] 1
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3
1 2 4 5 3 

回溯 j = 3
回溯  st[3] 0
j 4 st[4] 1
j 5 st[5] 1
回溯 j = 5
回溯  st[5] 0
回溯 j = 4
回溯  st[4] 0
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4
1 2 5 3 4 

回溯 j = 4
回溯  st[4] 0
j 5 st[5] 1
回溯 j = 3
回溯  st[3] 0
j 4 st[4] 0
j = 4
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 0
j = 3
1 2 5 4 3 

回溯 j = 3
回溯  st[3] 0
j 4 st[4] 1
j 5 st[5] 1
回溯 j = 4
回溯  st[4] 0
j 5 st[5] 1
回溯 j = 5
回溯  st[5] 0
回溯 j = 2
回溯  st[2] 0
j 3 st[3] 0
j = 3
j 1 st[1] 1
j 2 st[2] 0
j = 2
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5
1 3 2 4 5 

回溯 j = 5
回溯  st[5] 0
回溯 j = 4
回溯  st[4] 0
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 0
j = 4
1 3 2 5 4 

回溯 j = 4
回溯  st[4] 0
j 5 st[5] 1
回溯 j = 5
回溯  st[5] 0
回溯 j = 2
回溯  st[2] 0
j 3 st[3] 1
j 4 st[4] 0
j = 4
j 1 st[1] 1
j 2 st[2] 0
j = 2
j 1 st[1] 1
j 2 st[2] 1
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5
1 3 4 2 5 

回溯 j = 5
回溯  st[5] 0
回溯 j = 2
回溯  st[2] 0
j 3 st[3] 1
j 4 st[4] 1
j 5 st[5] 0
j = 5
j 1 st[1] 1
j 2 st[2] 0
j = 2
1 3 4 5 2

深搜好题分享:

HDU 1518 Square

NC13594 选择困难症

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值