【哈希!簡】康托展開與逆康托展開
阿新 • • 發佈:2018-11-17
[] return 動態 bits n-1 階乘 clu 排列 oid
康托展開是利用全排列與當前排列次序的映射建立一個簡易哈希表
康托展開
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; }
【哈希!簡】康托展開與逆康托展開