1. 程式人生 > >【康拓展開&逆康託展開】

【康拓展開&逆康託展開】

 百度百科就夠了

自己的體會:
康託展開是基於比他小的前面的個數來進行計算的
       另外康託展開也是一個數組到一個數的對映,因此也是可用於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);
}