zoukankan      html  css  js  c++  java
  • 【学习笔记】全排列

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

    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("
    ");
    		
    		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("
    ");
            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;
    }
    
  • 相关阅读:
    PreparedStatement/Statement处理insert update等操作时乱码,以及URL
    MySQL unique 注意
    web乱码解决了
    实用工具及Chrome插件及实用网站(持续更新中...)
    前端常用算法集合,持续更新...
    各种问题汇总解决方法,持续更新中...
    node实现自动化图片切割压缩, 部署页面
    移动端图片缩放插件Pinchzoom.js
    提示框简单封装
    模拟滚动条
  • 原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11634724.html
Copyright © 2011-2022 走看看