紫书第七章-----暴力求解法(全排列算法)

本文介绍了一种递归实现的全排列算法,并通过示例详细解释了其工作原理及去重方法。此外,还对比了使用STL中的next_permutation函数求解全排列的方法。

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

递归求全排列

/*
    本程序是递归实现全排列算法。
    思想是分别让谁打头。以1,2,3,4为例,一共只有4位,
    第一位可以分别让1,2,3,4打头,以第一位是1为例,
    第二位可以分别让2,3,4打头,以第二位是2为例,
    第三位可以分别让3,4打头,以第三位是4为例,
    第四位固定是4,输入此排列。
    其他情况类似输出。

    去重:以序列1,2,2,3为例,一共四位,一共3个不同的数,
    第一位可以让1,2,3打头,以第一位是1为例,
    第二位可以让2打头,以第二位为2为例,
    第三位的时候,由于前两位中已经出现了2,和第三位相同,不能让2第二次打头,所以,
    下面的算法为了去除重复排列,没有让1与第三个2交换。

*/

#include<iostream>
#include<algorithm>

using namespace std;

//去重复函数
bool is_swap(int a[],int st,int en){
    for(int i=st;i<en;i++){
        if(a[i]==a[en]) return false;
    }
    return true;
}
//全排列算法
void per(int a[],int st,int en){
    if(st==en){
        for(int i=0;i<en;i++)
            cout<<a[i]<<" ";
        cout<<endl;
    }
    else{
        for(int i=st;i<en;i++){
            if(is_swap(a,st,i)){
                swap(a[st],a[i]);
                per(a,st+1,en);
                swap(a[st],a[i]);//注意这里,解释一下,比如1,2,3,4的
                //全排列,以1打头的排列都求出后,重新调整为1,2,3,4,以
                //2打头的排列都求出后,重新调整为1,2,3,4等等,内层递归亦如此
            }
        }
    }
}

int main()
{
    int a[4]={1,2,2,3};
    per(a,0,4);
    return 0;
}

STL中的next_permutation求全排列


#include<iostream>
#include<algorithm>

using namespace std;

int main()
{
    int a[4]={1,2,2,3};
    sort(a,a+4);
    do{
        for(int i=0;i<4;i++)
            cout<<a[i]<<" ";
        cout<<endl;
    }while(next_permutation(a,a+4));
    return 0;
}

解答树

参考刘汝佳《算法竞赛入门经典》(第2版)

以上面递归求全排列的算法为例,下面的树展示了递归的过程。

第0层:(,,,)
第1层:(1,,,)、(2,,,)、(3,,,)、(4,,,)
第2程:
上面1打头的子结点是(1,2,,)、(1,3,,)、(1,4,,)
上面2打头的子结点是(2,1,,)、(2,3,,)、(2,4,,)
上面3打头的子结点是(3,1,,)、(3,2,,)、(3,4,,)
上面4打头的子结点是(4,1,,)、(4,2,,)、(4,3,,)

……

把上面的画成树,就是解答树。下面求一下解答树的结点个数:
第一层:n
第二层:n*(n-1)
第三层:n*(n-1)*(n-2)
……
第i层:n*(n-1)(n-2)…*(n-(i-1))=n!/(n-i)!
总的结点数是n!*(1/(n-1)!+1/(n-2)!+…+1/1!+1/0!),由泰勒展开式可知该式子趋向e*n!,则总结点数小于e*n!,又低第n层和第n-1层的结点数都是n!,最后两层的结点数目占据了2*n!,所以,多数情形下,解答树上的借电脑几乎全部来源于最后一两层。

参考刘汝佳《算法竞赛入门经典》(第2版):
如果某问题的解可以由多个步骤得到,而每个步骤都有若干种选择(这时候选方案集可能会依赖于先前作出的选择),且可以用递归枚举法实现,则它的工作方式可以用解答树描述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值