算法中的數學---康託展開

本文只是基於使用的角度來做一些簡單說明,不作證明!!

康託展開是一個全排列到一個自然數的雙射,常用於構建哈希表時的空間壓縮。 康託展開的實質是計算當前排列在所有由小到大全排列中的順序。
康託展開的公式爲:
x=a[n](n-1)!+a[n-1](n-2)!+…+a[1]*0!,x代表比當前排列小的排列的個數,因此最終我們需要的答案就是x+1,其中a[i]表示當前排列裏從i位置右側算起,比i位置的數還要小的數的個數,注意i從左到右依次爲n,n-1,n-2,…1。

舉個例子:
求{1,5,4,3,2}的康託展開。
首位是1,1的右邊比1小的數沒有,所以a[5]=0,注意這裏是a[5]而不是a[1],同理a[4]=3,a[3]=2,a[2]=1,a[1]=0;
所以x=0 * 4!+3 * 3!+2 * 2!+1 * 1!+0 * 0!=23,所以15432在所有包含12345的升序全排列中排在第24位!!!
代碼如下:

#include<bits/stdc++.h>
using namespace std;

//先預先算好0~9的階乘,方便計算 
int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
//x=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[1]*0!,注意i是從1~n,沒有0 
int Contor(char *a,int n) {
	int sum=0,small=0;
	for(int i=0;i<n;i++) {
		small=0;
		for(int j=i+1;j<n;j++) {
			if(a[j]<a[i]) {    //計算第i位右邊比該數還要小的數的個數 
				small++;
			}
		}
		sum+=small*fac[n-i-1];
		//例如12345,i=0時實際上對應着5 
		//順數第i位實際上對應着第n-i位 ,即a[n-i]=small,所以應該是small* ((n-i)-1)!
		//所以應該是small*fac[n-i-1] 
	}
	return sum+1;
}
int main() {
	int n,t;
	char a[10];
	cin>>n>>a;
	cout<<Contor(a,n);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章