【康拓展開&逆康託展開】
阿新 • • 發佈:2018-12-01
自己的體會:
康託展開是基於比他小的前面的個數來進行計算的
另外康託展開也是一個數組到一個數的對映,因此也是可用於hash,用於空間壓縮。比如在儲存一個序列,我們可能需要開一個數組,如果能夠把它對映成一個自然數, 則只需要儲存一個整數,大大壓縮空間。比如八數碼問題。
尤拉專案上的第二四題就需要用逆康拓展開的,不過這道題不是說的自然數,包括0,所以構建陣列的時候把0搞進去就好了
(尤拉專案上記得不贊成貼code的,
#include <bits/stdc++.h> using namespace std; static const int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//階乘 int cantor(int *a,int n){ //康託展開 int x=0; for(int i=0;i<n;++i){ int smaller=0; //當前位置之後小於它的個數 for(int j=i+1;j<n;++j){ if(a[j]<a[i]) ++smaller; } x+=fac[n-i-1]*smaller; } return x; } void decantor(int x,int n){ std::vector<int> v; std::vector<int> a; for(int i=0;i<n;++i) v.push_back(i);//這兒根據要求被排列的數字進行選擇有那幾個,不過要注意一下在0作為前導的時候 for(int i=1;i<=n;++i) v.push_back(i); for(int i=n;i;--i) { int r = x % fac[i-1]; int t= x / fac[i-1]; x=r; sort(v.begin(),v.end()); //從小到大排序 a.push_back(v[t]); //剩餘數裡第t+1個數為當前位 v.erase(v.begin()+t); // 移除選做當前位的數 } int sz=a.size(); for(int i=0;i<sz;++i) cout<<a[i]; cout<<endl; } int main(){ cantor(); decantor(1000000-1,10); }