【学习笔记】全排列

旧巷老猫 提交于 2019-11-30 18:19:11

今天模拟赛最后一题暴力骗分没骗到,特此下定决心搞懂全排列

1.全排列的定义和公式:

从n个数中选取m(m<=n)个数按照一定的顺序进行排成一个列,叫作从n个元素中取m个元素的一个排列。由排列的定义,显然不同的顺序是一个不同的排列。从n个元素中取m个元素的所有排列的个数,称为排列数。从n个元素取出n个元素的一个排列,称为一个全排列。全排列的排列数公式为n!,通过乘法原理可以得到。

2.时间复杂度:

n个数(字符、对象)的全排列一共有n!种,所以全排列算法至少时间O(n!)
的。如果要对全排列进行输出,那么输出的时间要O(n∗n!)

,因为每一个排列都有n个数据。所以实际上,全排列算法对大型的数据是无法处理的,而一般情况下也不会要求我们去遍历一个大型数据的全排列。

# 例题luogu全排列问题

法1:STL大法好!

#include<bits/stdc++.h>
#define rep(a,b,c) for(int a=b;a<=c;a++)
using namespace std;

int x[11];
int n;
int main()
{    
    scanf("%d",&n);
    
    rep(i,1,n)
    {
        x[i]=i,
        printf("    %d",i);
    } 
        
    while(next_permutation(x+1,x+1+n))
    {
        printf("\n");
        
        rep(i,1,n) 
            printf("    %d",x[i]);
    }
    return 0;
}

法2 dfs

#include<bits/stdc++.h> 
using namespace std;

int n;
int ans[15];//保存当前的方案
int use[15];

void dfs(int x)//X表示当前搜索到那个数
{
    if(x>n)
    {//如果N位都搜索完了,就输出方案并返回
        for(int i=1;i<=n;i++)
            printf("%5d",ans[i]);
        printf("\n");
        return;
    }
    
    for(int i=1;i<=n;i++)//从小到大枚举
        if(!use[i])
        {
            ans[x]=i;//保存到方案中
            use[i]=1;
            dfs(x+1);
            use[i]=0;
        }
}

int main()
{
    scanf("%d",&n);
    dfs(1);
}

法3 状压dp

震惊!蒟蒻复制了大佬的题解!

#include<bits/stdc++.h>
using namespace std;
//PS:这里就不用标记数组啦!s就相当于是标记数组了呢。)

int n,lg[1030],ans[10];

void dfs(int i,int s)//在dfs里加上一个形参s,是状态压缩的二进制数,1代表当前位置可以搜,反之是0。
{
    if(i>n)
    {
        for(int p=1;p<=n;p++)
            printf("%5d",ans[p]);
        return;
    }
    
    for(int ss=s;ss>0;ss-=ss&(-ss))//改一下递归部分的for(创建一个临时变量ss,替代当前一层的s;条件是s不为0;去掉ss的最后一位;)
    {
        int temp=ss&(-ss);//因为懒,就创建了一个临时变量。普及一下:一个数a求它二进制数的最右面一位1,就这么求:a&(-a)
        ans[i]=lg[temp];//因为状态压缩的每一位的数值就是2的(那一位)位数次方,所以lg数组起到了把位数上的值转变成位数的作用。
        dfs(i+1,s-temp);//这里递归时s减掉最后一位就行了。
    }
}
int main()
{
    scanf("%d",&n);
    lg[1]=1;
    for(int i=2;i<=n;i++)
        lg[1<<(i-1)]=i;//创建一个数组,下标是二的n次方的位置里存的是n;1<<几就是2的几次方。
        //(举个例子:下标是32的位置里存的是5,下标是1024的位置存的是10)
    dfs(1,(1<<n)-1);//第一次递归时所有位置都没搜
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!