zoukankan      html  css  js  c++  java
  • 17086 字典序的全排列

    17086 字典序的全排列

    时间限制:10000MS  内存限制:65535K
    提交次数:0 通过次数:0

    题型: 编程题   语言: G++;GCC;VC

     

    Description

    什么叫字典序,顾名思义就是按照字典的排列顺序。
    以字典序为基础,我们可以得出任意两个数字串的大小。比如 "1" < "12"<"13"。 就是按每个数字位逐个比较的结果。
    对于一个数字串的排列,可以知道最小的排列是从小到大的有序串“123456789”,而最大的排列串是从大到小的有序串
    “987654321”。这样对于“123456789”的所有排列,将他们排序,即可以得到按照字典序排序的所有排列的有序集合。
    
    因此,当我们知道当前的排列时,要获取下一个排列时,就可以找到有序集合中的下一个数(恰好比它大的)。比如,
    当前的排列时“123456879”,那么恰好比它大的下一个排列就是“123456897”。 当目前的排列是最大的时候,说明
    所有的排列都找完了。
    




    输入格式

    请输入字串的长度n和字符串。(n<10)
    
    注意:
    (1)字符串不含重复元素。
    (2)这里初始输入的字串不一定是排列的有序集合中最小的那个,即使不是最小的那个,输出也一定要按照从小
    到大的顺序输出。



    输出格式

    字典序的每个排列,按序号输出。



     

    输入样例

    3
    214



     

    输出样例

    1 124
    2 142
    3 214
    4 241
    5 412
    6 421



     

    提示

    这里两个办法来输出字典序的所有排列。
    
    方法一:
    可以用STL的next_permutation()函数,标准库全排列next_permutation()的返回值:
      bool类型。
    假设数列:d1d2d3d4…… 范围由[first,last)标记,调用next_permutation使数列
    逐次增大,这个递增过程按照字典序。
    
    C++ Reference中next_permutation的函数声明如下:
    #include <algorithm>
    bool next_permutation( iterator start, iterator end );
    The next_permutation() function attempts to transform the given range
    of elements [start,end) into the next lexicographically greater permutation
    of elements. If it succeeds, it returns true, otherwise, it returns false.
    
    所以,将输入的数字序列用sort()或qsort()排下序,先找到最小的字典序排列,然后不断
    调用next_permutation() 并输出,直至最后最大的一个。
    
    
    方法二:思路同方法一,但自行编写计算一个当前字符串的下一个字典序排列。
    设P是一个排列串:P = s[1]s[2]...s[n] = s[1]...s[j]...s[k]...s[n]
    
    1)从当前排列串的右端开始,找出第一个比右边数字小的数字的序号j
    (j从左端开始计算),即 j=max{i|s[i]<s[i+1]};
    
    2)在s[j]的右边的数字中,找出所有比s[j]大的数中最小的数字s[k],
    即 k=max{i|s[i]>s[j]}
    (对s[j]右边数来说,从右至左是递增的,因此k是所有大于s[j]的数字中序号最大者,
    序号虽最大但s[k]是处于s[j]右边且比s[j]大的数中的最小者);
    
    3)交换s[j]和s[k];
    
    4)再将s[j+1]...s[k-1]s[k]s[k+1]...s[n]倒转得到排列
     P' = s[1]s[2]...s[j]s[n]...s[k+1]s[k]s[k-1]...s[j+1],
    这里P'就是排列P的下一个排列。
    
    简单来说,就是对于给定的一个数,首先从右边找到第一个相邻“有序对”(这个“有序对”
    的定义是就是满足s[i]<s[i+1]最右边对)。
    现假设下一个要找的数比这个数大,且中间没有一个数比前者大、比后者小。然后再重新从
    右边起找出第一个比那个"有序对"的较小者要大的数,交换他们,再将那个较小数下标后面的
    子数组反转。
    
    总结一下:就是由后向前找替换数和替换点,然后由后向前找第一个比替换数大的数与替换数
    交换,最后颠倒替换点后的所有数据。
    

    我的代码实现

     1 #include<stdio.h>
     2 #include<math.h>
     3 #include<stdlib.h>
     4 
     5 #define N 10005
     6 
     7 
     8 int digui(int n){
     9     if(n==0)return 1;
    10     return n*digui(n-1);
    11 }
    12 
    13 int cmp(const void *a,const void *b){
    14     return *(char *)a-*(char *)b;
    15 }
    16 
    17 int findFirstMin(char a[],int n){
    18     int j;
    19     for(j=n;j>=0;j--){
    20         if(a[j]<a[j+1])return j;
    21         else continue;
    22     }
    23 }
    24 
    25 int findMinMax(char a[],int n,int j){//有问题,回去应该重新写过。 
    26     int minMax=a[j+1];
    27     int k=0;
    28     for(int i=j+1;i<=n;i++){
    29         if(a[i]>a[j]){
    30                 minMax=a[i];    
    31                 k=i;
    32             }
    33         else continue;
    34     }    
    35     return k;
    36 }
    37 
    38 
    39 void exchange(char *a,char *b){
    40     char temp;
    41     temp=*a;
    42     *a=*b;
    43     *b=temp;
    44 }
    45 
    46 
    47 
    48 void reverse(char a[],int n,int j){
    49     char *q,t,*p;
    50     p=a+j+1;
    51     for(q=a+n-1;p<q;++p,--q)
    52     {
    53         t=*p;
    54         *p=*q;
    55         *q=t;
    56     }
    57 }
    58 
    59 int main(){
    60     int n,i,j,k,m;
    61     scanf("%d",&n);
    62     char str[N];
    63     scanf("%s",str);
    64     qsort(str,n,sizeof(str[0]),cmp);
    65     printf("1 ");
    66 //    for(i=0;i<n;i++){
    67     printf("%s",str);
    68     printf("
    ");
    69     for(i=2;i<=digui(n);i++){
    70     j=findFirstMin(str,n);
    71     k=findMinMax(str,n,j);
    72     exchange(&str[j],&str[k]);
    73     reverse(str,n,j);
    74     printf("%d ",i);
    75     for(m=0;m<n;m++)
    76         printf("%c",str[m]);
    77     printf("
    ");
    78     }
    79 
    80     return 0;
    81 }
  • 相关阅读:
    Android游戏开发22:Android动画的实现J2me游戏类库用于Android开发
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第三部分,完整代码)
    使用OGR创建dxf格式矢量数据
    mysql 数据库引擎 MyISAM InnoDB 大比拼 区别
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第二部分)
    mysql 更改数据库引擎
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第一部分)
    android 数字键盘使用
    MySQL Innodb数据库性能实践
    eclipse : Error while performing database login with the driver null
  • 原文地址:https://www.cnblogs.com/double891/p/7855968.html
Copyright © 2011-2022 走看看