1. 程式人生 > >【雜湊!簡】康託展開與逆康託展開

【雜湊!簡】康託展開與逆康託展開

康託展開是利用全排列與當前排列次序的對映建立一個簡易雜湊表

 

康託展開

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; }