zoukankan      html  css  js  c++  java
  • 康托展开

    有一个关于排列问题的神奇的公式,康托展开

    维基百科是这样描述的:

    康托展开是一个全排列到一个自然数双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。

    以下称第x个全排列是都是指由小到大的顺序。

    这可以用来求一个排列是全排列中的第几个排列...

    关于公式的话,我觉得这个大佬写得非常棒,可以往这边看 ACdreamer

    按照我个人的理解是,an表示的是第n个数(从最后一个数字开始从1数)的前面有几个比它小的数字,(n-1)!表示的是(当前的数的位数-1,从1开始数位数)的阶乘。

    贴个例题

    标题: 排列序数

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

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

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

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

     这就是计算第几个全排列,如果不知道这个康托展开的话就很难做了...还是要多做题目 才能拓宽知识面...

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 long long a[17];
     4 
     5 int main(){
     6     a[0]=1;
     7     a[1]=1;
     8     for(int i=2; i<17; i++){
     9         a[i]=a[i-1]*i;
    10     }
    11     long long sum=0;
    12     string s="bckfqlajhemgiodnp";
    13     for(int i=0; i<17; i++){
    14         int tmp=0;
    15         for(int j=i+1; j<17; j++)
    16             if(s[j]<s[i]) tmp++;
    17         sum+=a[16-i]*tmp;
    18     }
    19     cout<<sum<<endl;
    20     
    21     return 0;
    22 }

    这个还有一个逆运用,就是已知一个数的第几个排列,让你去求这个数是什么...

    维基百科是这样描述的:

    既然康托展开是一个双射,那么一定可以通过康托展开值求出原排列,即可以求出n的全排列中第x大排列。

    如n=5,x=96时:

    首先用96-1得到95,说明x之前有95个排列.(将此数本身减去!)
    用95去除4! 得到3余23,说明有3个数比第1位小,所以第一位是4.
    用23去除3! 得到3余5,说明有3个数比第2位小,所以是4,但是4已出现过,因此是5.
    用5去除2!得到2余1,类似地,这一位是3.
    用1去除1!得到1余0,这一位是2.
    最后一位只能是1.
    所以这个数是45321.
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main(){
     5     long long p[16];
     6     p[0]=p[1]=1;
     7     for(int i=2; i<16; i++)
     8         p[i]=p[i-1]*i;
     9 
    10     int n, m, tmp;
    11     cin>>n>>m;
    12     tmp=n;
    13     vector<int>a;
    14     vector<int>v;
    15     for(int i=1; i<=n; i++){
    16         a.push_back(i);
    17     }
    18     m--;
    19     int t, r;
    20     for(int i=n; i>=1; i--){
    21         t=m/p[i-1];
    22         m=m%p[i-1];
    23         v.push_back(a[t]);
    24         a.erase(a.begin()+t);
    25         sort(a.begin(), a.end());
    26     }
    27     vector<int>::iterator it;
    28     for(it=v.begin(); it!=v.end(); it++){
    29         cout<<*it;
    30     }
    31     cout<<endl;
    32     
    33     return 0;
    34 }
  • 相关阅读:
    【leetcode】Binary Search Tree Iterator
    【leetcode】Palindrome Partitioning II
    【leetcode】Best Time to Buy and Sell Stock III
    【leetcode】Best Time to Buy and Sell Stock II
    【leetcode】Longest Consecutive Sequence
    【leetcode】Factorial Trailing Zeroes
    【leetcode】Simplify Path
    【leetcode】Generate Parentheses
    【leetcode】Combination Sum II
    【leetcode】Combination Sum
  • 原文地址:https://www.cnblogs.com/ledoc/p/6572714.html
Copyright © 2011-2022 走看看