【雜湊!簡】康託展開與逆康託展開
阿新 • • 發佈:2018-11-17
康託展開是利用全排列與當前排列次序的對映建立一個簡易雜湊表
康託展開
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; }