哈希!简康托展开与逆康托展开
Posted rign
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈希!简康托展开与逆康托展开相关的知识,希望对你有一定的参考价值。
康托展开是利用全排列与当前排列次序的映射建立一个简易哈希表
康托展开
ans=a0*(n-1)!+a1*(n-2)!+····+an*(n-n)!
找了半天解释,
就是ai表示剩下的数字中小于当前该数的个数,然后乘以剩下的数字的阶乘
意思也就说,剩下的数字中小于当前该数都可以代替当前数字,乘以阶乘就是剩下数字的全排列
比如CBAD,BA可以代替C。同时剩下三个数字也可以作为全排列
而逆康拓展开就是
通过计算当前位置外剩余的位置的数目,计算该阶乘,然后用给予的数字除以该数字,计算出来的除数就是比该数字小的个数,该数字变成余数(辗转相除)
在(1,2,3,4,5) 给出61可以算出起排列组合为34152
具体过程如下:
用 61 / 4! = 2余13,说明 ,说明比首位小的数有2个,所以首位为3。
用 13 / 3! = 2余1,说明 ,说明在第二位之后小于第二位的数有2个,所以第二位为4。
用 1 / 2! = 0余1,说明 ,说明在第三位之后没有小于第三位的数,所以第三位为1。
用 1 / 1! = 1余0,说明 ,说明在第二位之后小于第四位的数有1个,所以第四位为
#include<bits/stdc++.h> using namespace std; int f[]={1,1,2,6,24,120}; int a[5]; void contorExpanse(){//康拓展开 int ans=0; for(int i=0;i<5;i++){ int tmp=0; for(int j=i+1;j<5;j++){ if(a[j]<a[i]) tmp++;//计数 } ans+=tmp*f[5-i-1];//当前计数*阶乘 } cout<<ans<<endl; } void anticontorExpanse(int n){ //写的非常混乱 /* 整理一下思路就是设计两个动态数组作为可选和结果 从n->1开始,不断的辗转相除 计算当前小于该数的个数,从可选中选择,并删除 此时该数变成余数,重复步骤 */ vector<int>k; for(int i=1;i<=5;i++) k.push_back(i); vector<int>contor; int tmp=n; for(int i=5;i>=1;i--){ int cc=tmp/(f[i-1]);//计算当前的计数 contor.push_back(k[cc]); k.erase(k.begin()+cc);//删除 tmp=tmp%f[i-1];//变成余数 } for(int i=0;i<contor.size();i++) cout<<contor[i]<<" "; } int main(){ for(int i=0;i<5;i++) cin>>a[i]; contorExpanse(); int n; cin>>n; anticontorExpanse(n); return 0; }
以上是关于哈希!简康托展开与逆康托展开的主要内容,如果未能解决你的问题,请参考以下文章