第二篇 - 全排列问题 (深度优先搜索 DFS)

一、 问题描述:

设R={r1,r2,…,rn}是要进行排列的n个元素,求 R 的全排列 Perm(R)。

我们以洛谷 P1706 为例:https://www.luogu.com.cn/problem/solution/P1706

题目描述

输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n。

输出格式

由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5 个场宽。

输入输出样例

输入 

3

输出 

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

说明/提示

1≤n≤9

二、 问题分析:

有 DFS 基础的应该可以想到,应该按照下图中的思路进行搜索,但此时较难解决的是递归后续状态表示的问题,如当第一层为 2 时,我们应该如何置第二层为 1,3

第二篇 - 全排列问题 (深度优先搜索 DFS)_第1张图片

 首先想到,我们可以直接 DFS 然后剪枝

第二篇 - 全排列问题 (深度优先搜索 DFS)_第2张图片

算法如下所示:易知时间复杂度为 O(n^n) 

#include 

using namespace std;

int n,cnt=0, ans[10];
bool visited[10];

void dfs(int n){
    for(int i=1;i<=n;i++){
        if(!visited[i]){    //剪枝
            ans[cnt++]=i;
            if(cnt == n){
                for(int j=0;j>n;
    dfs(n);
}

按照最初的思路,我们知道算法的时间复杂度可为 n*(n-1)*(n-2).... 即 O ( n! ) 

lim(n!/n^n)=0 可知,O( n! ) 的算法时间复杂度要优于 O ( n^n )

 

参考相关教材,解决方法如下:

设(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列,则有

1. 递归关系: perm (R) 由 (r1)perm(R1),(r2)perm(R2) ,…, (rn)perm(Rn)构成,其中Ri=R-{ri}。

2. 终止条件:n=1时,Perm(R)=r ,r是R中的唯一元素

3. 参数设置:待排序数组 a,开始下标 l,终止下标 r

4. 实现思想:将当前状态整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列

三、 编写代码:

#include 

using namespace std;

int n,a[10];

void swap_fun(int &a, int &b){
    int temp=a;
    a=b;
    b=temp;
}

void dfs(int a[],int l, int r){
    if(l==r){
        for(int i=0;i>n;
    for(int i=0;i

四、 相关例题:

DFS:https://blog.csdn.net/sinat_40471574/article/details/89790495

你可能感兴趣的:(算法菜鸡之小题大论)