全排列的编码与解码——【康托展开及其逆运算】

来源:互联网 发布:淘宝怎么刷层级 编辑:程序博客网 时间:2024/06/05 00:32



参考过程:点击打开链接

参考代码:点击打开链接


康托展开表示的是当前排列在n个不同元素的全排列中的名次。比如213在这3个数所有排列中排第3。

 

那么,对于n个数的排列,康托展开为:

 

其中表示第i个元素在未出现的元素中排列第几。举个简单的例子:

 

对于排列4213来说,4在4213中排第3,注意从0开始,2在213中排第1,1在13中排第0,3在3中排第0,即:

 

,这样得到4213在所有排列中排第ans=20

 

代码实现:(从0开始计数)

 

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //康托展开  
  2. LL Work(char str[])  
  3. {  
  4.     int len = strlen(str);  
  5.     LL ans = 0;  
  6.     for(int i=0; i<len; i++)  
  7.     {  
  8.         int tmp = 0;  
  9.         for(int j=i+1; j<len; j++)  
  10.             if(str[j] < str[i]) tmp++;  
  11.         ans += tmp * f[len-i-1];  //f[]为阶乘  
  12.     }  
  13.     return ans;  //返回该字符串是全排列中第几大,从1开始  
  14. }  


 

康托展开的逆运算:就是根据某个排列的在总的排列中的名次来确定这个排列。比如:

 

求1234所有排列中排第20的是啥,那么就利用辗转相除法确定康托展开中的系数,然后每次输出当前未出现过的第个元素。

 

代码实现康托展开逆运算:

 

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //康托展开逆运算  
  2. void Work(LL n,LL m)  
  3. {  
  4.     n--;  
  5.     vector<int> v;  
  6.     vector<int> a;  
  7.     for(int i=1;i<=m;i++)  
  8.         v.push_back(i);  
  9.     for(int i=m;i>=1;i--)  
  10.     {  
  11.         LL r = n % f[i-1];  
  12.         LL t = n / f[i-1];  
  13.         n = r;  
  14.         sort(v.begin(),v.end());  
  15.         a.push_back(v[t]);  
  16.         v.erase(v.begin()+t);  
  17.     }  
  18.     vector<int>::iterator it;  
  19.     for(it = a.begin();it != a.end();it++)  
  20.         cout<<*it;  
  21.     cout<<endl;  
  22. }  



Problem C: 排列序数(21分)

Description

X星系的某次考古活动发现了史前智能痕迹。
这是一些用来计数的符号,经过分析它的计数规律如下:
(为了表示方便,我们把这些奇怪的符号用a~q代替)

abcdefghijklmnopq 表示0
abcdefghijklmnoqp 表示1
abcdefghijklmnpoq 表示2
abcdefghijklmnpqo 表示3
abcdefghijklmnqop 表示4
abcdefghijklmnqpo 表示5
abcdefghijklmonpq 表示6
abcdefghijklmonqp 表示7
.....

在一处石头上刻的符号是:
bckfqlajhemgiodnp

请你计算出它表示的数字是多少?

请输出该整数,不要输出任何多余的内容,比如说明或注释。

(注:蓝桥杯比赛时,此题为填空题,直接填写答案即可)

Input

Output

Sample Input

Sample Output


#include<stdio.h>#include<math.h>#include<stdlib.h>#include<string.h>long long fun(long long n){    long long s = 1;    for(int i = 1;i<=n;i++)        s*=i;    return s;}int main(){    int f[18] = {0};        int dig[] = {0,2,3,11,6,17,12,1,10,8,5,13,7,9,15,4,14,16};        long long sum = 0;        for(int i = 1;i<18;i++){            long long t = 0;            for(int j = 1;j<18;j++){                if(j==dig[i]){f[j]=1;break;}                if(f[j]==0)t++;            }            sum+=(t)*fun(18-1-i);//此处康托展开式公式        }        printf("%lld",sum);    return 0;}



[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <iostream>  
  4. #include <algorithm>  
  5. using namespace std;  
  6. #define ll long long  
  7.   
  8. ll pow(ll a)  
  9. {  
  10.     ll s = 1;  
  11.     for(ll i = 1; i <= a; i++)  
  12.         s *= i;  
  13.     return s;  
  14. }  
  15.   
  16. int main()  
  17. {  
  18.     char s[18]="bckfqlajhemgiodnp";//17长度  
  19.     ll a, ans = 0, k;  
  20.     for(int i = 0; i < 16; i++)  
  21.     {  
  22.         k = 0;  
  23.         for(int j = i+1; j < 17; j++)  
  24.             if(s[i] > s[j]) k++;  
  25.         ans += k * pow(16-i);  
  26.     }  
  27.     printf("%lld\n", ans);  
  28.     return 0;  
  29. }  
  30.   
  31. /** 
  32. 根据题意,可知题目计算的为全排列的次数 
  33. 然后找规律 
  34. 0123 0   0*3! + 0*2! + 0*1! = 0 
  35. 0132 1   0*3! + 0*2! + 1*1! = 1 
  36. 0213 2   0*3! + 1*2! + 0*1! = 2 
  37. 0231 3   0*3! + 1*2! + 1*1! = 3 
  38. 0312 4   0*3! + 2*2! + 0*1! = 4 
  39. 0321 5   0*3! + 2*2! + 1*1! = 5 
  40. 1023 6   1*3! + 0*2! + 0*1! = 6 
  41. 1032 7   1*3! + 0*2! + 1*1! = 7 
  42. 1203 8   1*3! + 1*2! + 0*1! = 8 
  43. 1230 9   1*3! + 1*2! + 1*1! = 9 
  44. 1302 10  1*3! + 2*2! + 0*1! = 10 
  45. 1320 11  1*3! + 2*2! + 1*1! = 11 
  46. 2013 12  2*3! + 0*2! + 0*1! = 12 
  47. 2031 13  2*3! + 0*2! + 1*1! = 13 
  48. 2103 14  2*3! + 1*2! + 0*1! = 14 
  49. 2130 15  2*3! + 1*2! + 1*1! = 15 
  50. 2301 16  2*3! + 2*2! + 0*1! = 16 
  51. 2310 17  2*3! + 2*2! + 1*1! = 17 
  52. 3012 18  3*3! + 0*2! + 0*1! = 18 
  53. 3021 19  3*3! + 0*2! + 1*1! = 19 
  54. 3102 20  3*3! + 1*2! + 0*1! = 20 
  55. 3120 21  3*3! + 1*2! + 1*1! = 21 
  56. 3201 22  3*3! + 2*2! + 0*1! = 22 
  57. 3210 23  3*3! + 2*2! + 1*1! = 23 
  58.  
  59. 可以得出规律,比后面大的个数 * (i-1)! 
  60. 查询资料可知,此为[康托展开式]
  61. 答案:22952601027516 
  62. */  


0 0
原创粉丝点击