全排序与康拓展开
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