• 全排序各种求法


     

    全排序与康拓展开

    n=3

    全排列:

    123

    132

    213

    231

    312

    321

    每个数列由1~n组成,且出现一次。

    对于第一个位置,有n种选择,对于第二个位置,有(n-1)种选择,…,对于最后一个位置,有1种选择,所有共有n!种排序方法。

    数列从小到大排序(或从大到小排序,或不排序))。

    数列:x[n]_x[n-1]_…_x[1] (从小到大排列后为1~n)

    该数列的编号:num=a[n]*(n-1)!+a[n-1]*(n-2)!+a[1]*0!

    a[k]:x[k]在当前未出现的元素中排在第(a[k]+1)个

    而num:0~n!-1,a[k]<=k-1。

    证明:

    若x[n]_x[n-1]_…_x[k+1]_(min)的起始编号为x,

    则x[n]_x[n-1]_…_x[k+1]_x[k]_(min)的起始编号为x+a[k]*(k-1)!,即某一个x[k]在原来的基础上加上a[k]*(k-1)!。

    注意0!=1。因为定义C(x,y)=x!/(x-y)!/y!,而C(x,0)=x!/x!/0!=1,所以定义0!=1。

    求全排序:

    I.

    dfs1,时间效率高,但数列并没有排序。

     1 #include <iostream>
     2 #define maxn 15
     3 using namespace std;
     4  
     5 //每一位的确定:还未使用的数 依次被选择(swap(a[pos],a[i]);  //以a[i]作为第pos位)
     6 //所以数列不会产生重复
     7  
     8 //数列没有排序!
     9 //第pos位有1次未交换位置,(n-pos)次交换位置
    10 //而与第pos位中的某个数延展得到的数有(n-pos)!个
    11 //交换两数和交换回来需要6次操作
    12 //(n-1)!*(n-1)+(n-2)!*(n-2)+…+1!*1=n!-1
    13 //O(6*(n!-1))=O(6n!),时间复杂度很低,创建全排序效率很高!
    14  
    15 long a[maxn+1],n;
    16  
    17 void swap(long &a,long &b)
    18 {
    19     long temp;
    20     temp=a;
    21     a=b;
    22     b=temp;
    23 }
    24  
    25 void dfs(long pos)
    26 {
    27     long i;
    28     if (pos==n)
    29     {
    30         for (i=1;i<=n;i++)
    31             cout<<a[i]<<" ";
    32         cout<<endl;
    33     }
    34     else
    35     {
    36         dfs(pos+1);
    37         for (i=pos+1;i<=n;i++)
    38         {
    39             swap(a[pos],a[i]);  //以a[i]作为第pos位
    40             dfs(pos+1);
    41             swap(a[pos],a[i]);
    42         }
    43     }
    44 }
    45  
    46 int main()
    47 {
    48     long i;
    49     cin>>n;
    50     for (i=1;i<=n;i++)
    51         a[i]=i;
    52     dfs(1);
    53     return 0;
    54 }

    II.

    dfs2,时间复杂度高

     1 #include <iostream>
     2 #define maxn 15
     3 using namespace std;
     4  
     5 //dfs:要是哪个数未被使用,就使用该数
     6 //由于是按从小到大的顺序判断,所以数列也是从小到大排序
     7 //dfs执行完后要改变为原来的状态(回溯):vis[i]=true;(标记该数未被使用)
     8 //dfs时间复杂度较高
     9  
    10 long n,a[maxn+1];
    11 bool vis[maxn+1];
    12  
    13 void dfs(long pos)
    14 {
    15     long i;
    16     if (pos==n+1)
    17     {
    18         for (i=1;i<=n;i++)
    19             cout<<a[i]<<" ";
    20         cout<<endl;
    21     }
    22     else
    23     {
    24         for (i=1;i<=n;i++)
    25             if (vis[i])
    26             {
    27                 vis[i]=false;
    28                 a[pos]=i;
    29                 dfs(pos+1);
    30                 vis[i]=true;
    31             }
    32     }
    33 }
    34  
    35 int main()
    36 {
    37     long i;
    38     cin>>n;
    39     for (i=1;i<=n;i++)
    40     {
    41         vis[i]=true;
    42         a[i]=i;
    43     }
    44     dfs(1);
    45     return 0;
    46 }

    III.

    小到大排序,由第k个数推出第(k+1)个数

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define maxn 15
     4  
     5 //编号为k的数列通过一系列操作改变为编号为k+1的数列
     6  
     7 int main()
     8 {
     9     long j,k,n,temp,x,y,a[maxn+1];
    10     long long i,s;
    11     scanf("%ld",&n);
    12     //posibility
    13     s=1;
    14     for (i=2;i<=n;i++)
    15         s=s*i;
    16     for (i=1;i<=n;i++)
    17         a[i]=i;
    18     for (k=1;k<=n;k++)
    19         printf("%ld ",a[k]);
    20     printf("
    ");
    21  
    22     for (i=1;i<s;i++)
    23     {
    24         //4 8 7 6 5 3 2 1
    25         //5 8 7 6 4 3 2 1
    26         //5 1 2 3 4 6 7 8
    27  
    28         //从尾到头,找到第一个下降的a[j]
    29         for (j=n-1;j>=1;j--)
    30             if (a[j]<a[j+1])
    31                 break;
    32         //a[j]:从尾到a[j],找到第一个比a[j]大的数a[k]
    33         for (k=n;k>j;k--)
    34             if (a[k]>a[j])
    35                 break;
    36         //交换a[j]和a[k]的值
    37         temp=a[j];
    38         a[j]=a[k];
    39         a[k]=temp;
    40         //数组:j+1~n reverse
    41         x=j+1;
    42         y=n;
    43         while (x<y)
    44         {
    45             temp=a[x];
    46             a[x]=a[y];
    47             a[y]=temp;
    48             x++;
    49             y--;
    50         }
    51         for (k=1;k<=n;k++)
    52             printf("%ld ",a[k]);
    53         printf("
    ");
    54     }
    55     return 0;
    56 }

    IV.

    康拓展开,通过数的编号逆推出数

     1 #include <iostream>
     2 #define maxn 15
     3 using namespace std;
     4  
     5 //数列:x[n]_x[n-1]_…_x[1] (从小到大排列后为1~n)
     6 //该数列的编号:num=a[n]*(n-1)!+a[n-1]*(n-2)!+a[1]*0!
     7 //a[k]:x[k]在当前未出现的元素中排在第(a[k]+1)个
     8 //num:0~n!-1 a[k]<=k-1
     9  
    10 //时间复杂度:
    11 //寻找数列:x[n]_x[n-1]_…_x[1]
    12 //1~x[n];1~x[n-1];…;1~x[1],总x[n]+x[n-1]+…+x[1]=1+2+…+n=n*(n+1)/2
    13 //数列共有n!个,所以O(n*(n+1)/2*n!),这是个大概值
    14  
    15 int main()
    16 {
    17     long n,value[maxn+1],i,j,k,num,pos;
    18     bool vis[maxn+1];
    19     cin>>n;
    20     value[1]=1;
    21     value[2]=1;
    22     for (i=2;i<=n;i++)
    23         value[i+1]=value[i]*i;
    24     for (i=0;i<value[n+1];i++)
    25     {
    26         for (j=1;j<=n;j++)
    27             vis[j]=false;
    28         num=i;
    29         for (j=n;j>=1;j--)
    30         {
    31             pos=num/value[j];
    32             num-=pos*value[j];
    33             //assume TTFTTTFFT
    34             k=0;
    35             while (pos>=0)
    36             {
    37                 pos--;
    38                 k++;
    39                 while (vis[k])
    40                     k++;
    41             }
    42             vis[k]=true;
    43             cout<<k<<" ";
    44         }
    45         cout<<endl;
    46     }
    47     return 0;
    48 }

    修改后速度提高:

     1 #include <iostream>
     2 #define maxn 15
     3 using namespace std;
     4  
     5 //数列:x[n]_x[n-1]_…_x[1] (从小到大排列后为1~n)
     6 //该数列的编号:num=a[n]*(n-1)!+a[n-1]*(n-2)!+a[1]*0!
     7 //a[k]:x[k]在当前未出现的元素中排在第(a[k]+1)个
     8 //num:0~n!-1 a[k]<=k-1
     9  
    10 //时间复杂度:
    11 //寻找数列:x[n]_x[n-1]_…_x[1]
    12 //找x[k]次需要a[k]次,寻找一个数列需要a[n]+a[n-1]+…+a[1]次操作
    13  
    14 //a[k]:0~k-1出现概率相同,平均值为(k-1)/2
    15 //所以a[n],a[n-1],…,a[1]的平均值为(n-1)/2,(n-2)/2,…,0
    16 //数列共有n!个,所以O(((n-1)/2+(n-2)/2+…+0)*n!)=O((n-1)*n/4*n!)
    17 //这个值是被低估的,但比上个方法快
    18  
    19 int main()
    20 {
    21     long n,value[maxn+1],i,j,num,pos,next[maxn+1],s,head;
    22     cin>>n;
    23     value[1]=1;
    24     value[2]=1;
    25     for (i=2;i<=n;i++)
    26         value[i+1]=value[i]*i;
    27     for (i=0;i<value[n+1];i++)
    28     {
    29         for (j=1;j<=n;j++)
    30             next[j]=j+1;
    31         head=1;
    32         num=i;
    33         for (j=n;j>=1;j--)
    34         {
    35             pos=num/value[j];
    36             num-=pos*value[j];
    37             //assume TTFTTTFFT
    38             if (pos==0)
    39             {
    40                 cout<<head<<" ";
    41                 head=next[head];
    42             }
    43             else
    44             {
    45                 s=head;
    46                 while (pos>1)
    47                 {
    48                     s=next[s];
    49                     pos--;
    50                 }
    51                 cout<<next[s]<<" ";
    52                 next[s]=next[next[s]];
    53             }
    54         }
    55         cout<<endl;
    56     }
    57     return 0;
    58 }

    康拓展开求编号

    s[1],s[2],…,s[n]都不相同,且{s[1],s[2],…,s[n]}={1,2,…,n}

       X=(s[1],s[2],…,s[n])

    Number(X)=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[1]*0!

    a[i]:数s[i]比s[i+1]~s[n]大的个数或者s[i]-1 减去s[i]比s[1]~s[i-1]大的数目

    (因为n个数从1~n且都不相同,比s[i]小的数有s[i]-1个)

       如X=2413

       Number(2413)=1*3!+2*2!+0*1!+0*0!=10

    求一个数X的编号(从小到大排序,最小数的编号为0)

    Code:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #define maxn 15
      4  
      5 int main()
      6 {
      7     long n,i,j,x[maxn+1],value[maxn+1],pos,ans=0;
      8     scanf("%ld",&n);
      9     for (i=1;i<=n;i++)
     10         scanf("%ld",&x[i]);
     11     //value[1]=1;
     12     value[2]=1;
     13     for (i=2;i<n;i++)
     14         value[i+1]=value[i]*i;
     15     //不用考虑最后1位,最后一位对应的值为0
     16     for (i=1;i<n;i++)
     17     {
     18         pos=0;
     19         for (j=i+1;j<=n;j++)
     20             if (x[i]>x[j])
     21                 pos++;
     22         ans+=pos*value[n+1-i];
     23     }
     24     printf("%ld
    ",ans);
     25     return 0;
     26 }
     27  
     28 Code:(高精度)
     29 #include <iostream>
     30 #include <memory.h>
     31 using namespace std;
     32  
     33 long max(long a,long b)
     34 {
     35     if (a>b)
     36         return a;
     37     else
     38         return b;
     39 }
     40  
     41 int main()
     42 {
     43     long n,i,j,s[100],value[100][100],len[100],g,ans[100],lenans,c[100],lenc;
     44     cin>>n;
     45     for (i=1;i<=n;i++)
     46         cin>>s[i];
     47     value[0][1]=0;
     48     len[1]=1;
     49     value[1][1]=1;
     50     len[1]=1;
     51     for (j=2;j<n;j++)
     52     {
     53         value[j][1]=0;
     54         for (i=1;i<=len[j-1];i++)
     55         {
     56             value[j][i]+=value[j-1][i]*j;
     57             if (value[j][i]>=10000)
     58             {
     59                 value[j][i+1]=value[j][i]/10000;
     60                 value[j][i]=value[j][i]%10000;
     61             }
     62             else
     63                 value[j][i+1]=0;
     64         }
     65         if (value[j][i]==0)
     66             len[j]=len[j-1];
     67         else
     68             len[j]=len[j-1]+1;
     69     }
     70     /*
     71     value[0]=0;
     72     value[1]=1;
     73     for (i=2;i<n;i++)
     74         value[i]=value[i-1]*i;
     75     */
     76     lenans=1;
     77     memset(ans,0,sizeof(ans));
     78     for (i=1;i<=n;i++)
     79     {
     80         g=0;
     81         for (j=i+1;j<=n;j++)
     82             if (s[i]>s[j])
     83                 g++;
     84         //ans+=g*value[n-i];
     85         c[1]=0;
     86         for (j=1;j<=len[n-i];j++)
     87         {
     88             c[j]+=g*value[n-i][j];
     89             if (c[j]>=10000)
     90             {
     91                 c[j+1]=c[j]/10000;
     92                 c[j]=c[j]%10000;
     93             }
     94             else
     95                 c[j+1]=0;
     96         }
     97         if (c[j]==0)
     98             lenc=j-1;
     99         else
    100             lenc=j;
    101         lenans=max(lenans,lenc);
    102         for (j=1;j<=lenans;j++)
    103         {
    104             ans[j]+=c[j];
    105             if (ans[j]>=10000)
    106             {
    107                 ans[j+1]++;
    108                 ans[j]-=10000;
    109             }
    110         }
    111         if (ans[j]!=0)
    112             lenans++;
    113     }
    114     //cout<<ans<<endl;
    115     cout<<ans[lenans];
    116     for (i=lenans-1;i>=1;i--)
    117         if (ans[i]>=1000)
    118             cout<<ans[i];
    119         else if (ans[i]>=100)
    120             cout<<"0"<<ans[i];
    121         else if (ans[i]>=10)
    122             cout<<"00"<<ans[i];
    123         else
    124             cout<<"000"<<ans[i];
    125     cout<<endl;
    126     return 0;
    127 }

    高精度:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define maxn 100
     4 #define maxw 100
     5 #define div 10000
     6  
     7 int main()
     8 {
     9     long n,pos,i,j,x[maxn+1],value[maxn+1][maxw+1],len[maxn+1],ans[maxw+1],lenans,s[maxw+1],lens;
    10     scanf("%ld",&n);
    11     for (i=1;i<=n;i++)
    12         scanf("%ld",&x[i]);
    13     value[2][1]=1;
    14     len[2]=1;
    15     //高+/*低 低<除数,最多进1位
    16     for (i=2;i<n;i++)
    17     {
    18         value[i+1][0]=0;
    19         for (j=1;j<=len[i];j++)
    20         {
    21             value[i+1][j]=value[i][j]*i+value[i+1][j-1]/div;
    22             value[i+1][j-1]=value[i+1][j-1]%div;
    23         }
    24         if (value[i+1][j-1]>=div)
    25         {
    26             value[i+1][j]=value[i+1][j-1]/div;
    27             value[i+1][j-1]=value[i+1][j-1]%div;
    28             len[i+1]=j;
    29         }
    30         else
    31             len[i+1]=j-1;
    32     }
    33  
    34 //    for (i=2;i<n;i++)
    35 //        value[i+1]=value[i]*i;
    36     //不用考虑最后1位,最后一位对应的值为0
    37     for (i=1;i<=maxw;i++)
    38         ans[i]=0;
    39     lenans=1;
    40     s[0]=0;
    41     for (i=1;i<n;i++)
    42     {
    43         pos=0;
    44         for (j=i+1;j<=n;j++)
    45             if (x[i]>x[j])
    46                 pos++;
    47  
    48         for (j=1;j<=len[n+1-i];j++)
    49         {
    50             s[j]=value[n+1-i][j]*pos+s[j-1]/div;
    51             s[j-1]=s[j-1]%div;
    52         }
    53         if (s[j-1]>=div)
    54         {
    55             s[j]=s[j-1]/div;
    56             s[j-1]=s[j-1]%div;
    57             lens=j;
    58         }
    59         else
    60             lens=j-1;
    61  
    62         for (j=1;j<=lens;j++)
    63         {
    64             ans[j]+=s[j];
    65             if (ans[j]>=div)
    66             {
    67                 ans[j+1]++;
    68                 ans[j]-=div;
    69             }
    70         }
    71         if (ans[lenans+1]!=0)
    72             lenans++;
    73 //        ans+=pos*value[n+1-i];
    74     }
    75     printf("%ld",ans[lenans]);
    76     for (i=lenans-1;i>=1;i--)
    77         if (ans[i]>=1000)
    78             printf("%ld",ans[i]);
    79         else if (ans[i]>=100)
    80             printf("0%ld",ans[i]);
    81         else if (ans[i]>=10)
    82             printf("00%ld",ans[i]);
    83         else
    84             printf("000%ld",ans[i]);
    85     printf("
    ");
    86     return 0;
    87 }

    Input:

    100

    100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61

     60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21

     20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

    Output:

    93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916863999999999999999999999999

  • 相关阅读:
    Android Studio 使用 Gradle 打包 Jar
    图片相关
    判断SIM卡状态,获取SIM卡信息
    SwipeRefreshLayout完美添加及完善上拉加载功能
    环境变量配置文件,本地登录前提示信息/etc/issue
    变量声明declare,简单运算符运算,变量测试与内容替换
    变量:用户自定义变量(本地变量),环境变量,位置参数变量,预定义变量
    多命令顺序执行,dd命令,管道|,grep,通配符,其他特殊符号
    历史命令~/.bash_history,查看所有别名alias,命令执行顺序,命令行常用快捷键,输入输出重定向,wc统计字节单词行数
    查看当前支持的shell,echo -e相关转义符,一个简单shell脚本,dos2unix命令把windows格式转为Linux格式
  • 原文地址:https://www.cnblogs.com/cmyg/p/6810480.html
Copyright © 2020-2023  润新知