zoukankan      html  css  js  c++  java
  • 杭电acm 排列2

    题目地址:http://acm.hdu.edu.cn/game/entry/problem/show.php?chapterid=1&sectionid=3&problemid=17

    这题的核心算法就是排列问题:

    就目前常用的排列算法有两种:

    一种是按字典列出排序,C++ STL所使用的方法,能够支持重复元素的全排列。

    另外一种是使用递归生成排序。

    先说容易理解的一种方法,使用递归生成排序:

    例如1,2,3,4,这个序列。

    最开始,也就是递归最外层我们可以将其分成:

    1    2,3,4,

    2    1,3,4

    3    1,2,4

    4    1,2,3

    这四个子分组:

    然后递归到某一个子分组当中比如2,3,4

    于是就可以得到:

    2  3,4

    3  2,4

    4  2,3

    这三个子分组。

    再次递归进入某一个分组:

    3    4

    4    3

    当只有第一个数的时候,便不可分了,打印该排列。

    于是递归的算法可以写成:

    perm(int *list,int l,int r){
        if(l>r){//递归结束条件
            for(int i=0;i<4;i++){
                printf("%d ",list[i]);
            }
            break;
        }else{
            for(int i=l;i<=r;i++){
                swap(&list[i],&list[l]);//传递引用,否则交换失败
                perm(list,l+1,r);
                swap(&list[i],&list[l]);//交换回来,保证原数组不变
            }
        }
    }

    按照字典列出排序的方法:

    它的思想就是不断的找到一个排列中的下一个排列,而且这两个排列之间不会再有任何排列,整个排列都是从小到大排序的,

    比如一个任意排列:134987652,我们如何确定下一个排列是多少呢?

    从右往左看,第一个小于它的右边的数是4,,13(4)987652。

    然后从4右边的数字开始,我们找到最后一个大于它的数字5,1349876(5)2.。

    然后调换4,5,得到数字串:13(5)9876(4)2.

    翻转5 后面的序列我们得到:13(5)2(4)6789

    我们获得的这个序列就是134987652的下一个排列的数字。

    为什么呢?

    我们仔细研究就会发现:

    1. 在第一步从右往左寻找第一个比他右边小的数字的时候,就是确定最后一个递减子序列的位置,直接将其翻转就是该子序列的字典最小值,我们在翻转之前需要变化递减子序列的前一个数字也就是4,[13(4)987652]。

    2. 确定该子序列的前一个数,我们将递减子序列当中的大于该数的最小数与它交换,在例子中也就是4和5交换,13(5)9876(4)2,于是我们可以知道,调换以后,递减子序列9876(4)2依然保持递减的特性,而递减子序列之前的数字增大,递减子序列之前的序列13(5)在字典序上恰好增大到下一个字典子序列,这时,我们需要递减子序列的最小字典子序列。

    3. 我们翻转递减子序列,得到递减子序列的最小字典序987652,于是就得到了整个序列的递增的下一个字典序列。

    字典实现排列算法的代码如下:

    bool next_perm(int *list,int l,int r){
    	int k=r;
    	while(k>l&&list[k-1]>=list[k])k--;
    	if(k==l){
    		//已经不存在递增部分,此时已经到达最后一个数字。
    		return false;
    	}
    	int j=k;//取 k-1
    	while(j<=r&&list[j]>list[k-1])j++;
    	//取j-1
    	swap(list[k-1],list[j-1]);//交换list[k-1],list[j-1]
        inverse(list,k,r);
        for(int i=l;i<=r;i++){
        	printf("%d ",list[i]);
        }
        printf("
    ");
        return true;
    }

    说了这么多,回到排列2这道题目上,我的ac代码如下:

    #include<iostream>
    
    #include<cstdio>
    
    #include<cstdlib>
    
    #include<algorithm>
    
    #include<set>
    
    using namespace std;
    
    
    set<int> s;
    
    
    int cnt=0;
    
    void init(){
    
    cnt=0;
    
    s.clear();
    
    }
    
    
    void swap(int *a,int *b){
    
    int m=*a;
    
    *a = *b;
    
    *b = m;
    
    }
    
    //递归算法
    
    void perm(int *list, int l,int r){
    
    if(l>r){
    
    int v=0;
    
    for(int i=0;i<4;i++){
    
    v=v*10+list[i];
    
    }
    
    s.insert(v);
    
    }else{
    
    for(int i=l;i<=r;i++){
    
    swap(&list[l],&list[i]);
    
    perm(list,l+1,r);
    
    swap(&list[l],&list[i]);
    
    }
    
    }
    
    
    }
    
    int main(){
    
    int list[4];
    
    bool first=true;
    
    while(scanf("%d %d %d %d",&list[0],&list[1],&list[2],&list[3])==4){
    
    if(list[0]==0&&list[1]==0&&list[2]==0&&list[3]==0){
    
    break;
    
    }
    
       if(!first)printf("
    ");
    
       first = false;
    
       init();
    
    perm(list,0,3);
    
    set<int>::iterator iter;
    
    int header = -1;
    
    for(iter=s.begin();iter!=s.end();iter++){
    
    int value = *iter;
    
    if(value>=1000){
    
    if(header==-1){
    
    header = value/1000;
    
    printf("%d",value);
    
    continue;
    
    }
    
    if(header==value/1000){
    
    printf(" %d",value);
    
    continue;
    
    }
    
    if(header!=value/1000&&header!=-1){
    
    header = value/1000;
    
    printf("
    %d",value);
    
    continue;
    
    }
    
    }
    
    }
    
    printf("
    ");
    
    }
    
    return 0;
    
    }
  • 相关阅读:
    TP3.2写上下篇
    TP3.2写分页
    TP3.2写提交的验证码验证
    thinkphp5.0学习笔记(四)数据库的操作
    thinkphp5.0学习笔记(三)获取信息,变量,绑定参数
    Windows下用Composer引入官方GitHub扩展包
    glog的安装使用
    实现strStr()函数
    何时将析构函数声明为私有?
    memcpy内存重叠
  • 原文地址:https://www.cnblogs.com/jackwuyongxing/p/4526002.html
Copyright © 2011-2022 走看看