有所摘抄,但重要的是自己的想法。
康托展開是乙個全排列到乙個自然數的雙射,常用於構建雜湊表時的空間壓縮。 康托展開的實質是計算當前排列在所有由小到大全排列中的順序,因此是可逆的。
x = a[n]*(n-1)! + a[n-1]*(n-2)! + ... + a[i]*(i-1)! + ... + a[1]*0!
index: 1 2 ... n-i+1 ... n
其中,a[i]為整數,並且0<=a[i]
a[i] 是:假設 一串數字中第index個元素為e, a[i]表示第index個數e之後的數比e小的數的個數
x表示序列是全排列中第幾個排列(從0開始)。
舉個例子:
原序列: 1 2 3 4 5 6 7 8
求: 3 5 7 4 1 2 9 6 8
x = 2*8! + 3*7! + 4*6! + 2*5! + 0*4! + 0*3! + 2*2! + 0*1! + 0*0! = 98884.
解釋:
排列的第一位是3,比3小的數有兩個,以這樣的數開始的排列有8!個,因此第一項為2*8!
排列的第二位是5,比5小的數有1、2、3、4,由於3已經出現,因此共有3個比5小的數,這樣的排列有7!個,因此第二項為3*7!
以此類推,直至0*0!
用途:
顯然,n位(0~n-1)全排列後,其康托展開唯一且最大約為n!,因此可以由更小的空間來儲存這些排列。由公式可將x逆推出對應的全排列。
總之就是用來壓縮空間的。。本人也不大懂。
例題:
描述 現在有"abcdefghijkl」12個字元,將其所有的排列中按字典序排列,給出任意一種排列,說出這個排列在所有的排列中是第幾小的?
輸入每行輸入一行字串,保證是a~l這12個字元的某種排列
eof結束 輸出
輸出乙個整數,代表這個排列排在第幾位
樣例輸入1
abcdefghijkl樣例輸出1abcdefghiklj
gfkedhjblcia
14260726926
#include #include #define ll long long
using namespace std;
int factorial(int l)
int main()
printf("%lld\n", ans);
} return 0;
}
另外,康托展開的逆運算,即通過知道它是第幾個全排列求全排列
例1 的全排列,並且已經從小到大排序完畢
(1)找出第96個數
首先用96-1得到95
用95去除4! 得到3餘23
有3個數比它小的數是4
所以第一位是4
用23去除3! 得到3餘5
有3個數比它小的數是4但4已經在之前出現過了所以第二位是5(4在之前出現過,所以實際比5小的數是3個)
用5去除2!得到2餘1
有2個數比它小的數是3,第三位是3
用1去除1!得到1餘0
有1個數比它小的數是2,第二位是2
最後乙個數只能是1
所以這個數是45321
(2)找出第16個數
首先用16-1得到15
用15去除4!得到0餘15
用15去除3!得到2餘3
用3去除2!得到1餘1
用1去除1!得到1餘0
有0個數比它小的數是1
有2個數比它小的數是3 但由於1已經在之前出現過了所以是4(因為1在之前出現過了所以實際比4小的數是2)
有1個數比它小的數是2 但由於1已經在之前出現過了所以是3(因為1在之前出現過了所以實際比3小的數是1)
有1個數比它小得數是2 但由於1,3,4已經在之前出現過了所以是5(因為1,3,4在之前出現過了所以實際比5小的數是1)
最後乙個數只能是2
所以這個數是14352
最後,還有乙個全排列函式 :next_permutation函式
這是乙個求乙個排序的下乙個排列的函式,可以遍歷全排列,要包含標頭檔案
與之完全相反的函式還有prev_permutation
但做本題是會超時(不用想也是,乙個乙個求肯定tle)
該函式可以對很多態別的陣列序列進行求下乙個字典序排列,即按全排的順序求下乙個排序序列
這裡也貼一下本題的tle**(嘿嘿)
//tle
#include #include #include #include using namespace std;
int main()
res = 1;
while(next_permutation(a, a+12))
} }return 0;
}
此函式各種型別的用法詳解:
2017/4/1日增: 1.
//康拓**實現
#include using namespace std;
int factor(int k)
int main()
cout << ans+1 << endl; //最小序列ans為0,同理ans+1;
} return 0;
}
2.
//逆康拓**實現
#include using namespace std;
int factor(int k)
int ans[105], book[105];
int main()
ans[i] = j-1; //當找到該數時j多加了一次1
book[j-1] = 1;
} for(int i = 1; i <= m; ++i)
printf("%d", ans[i]);
printf("\n");
} return 0;
}
康托展開及其逆運算
康托展開的wiki介紹 申明 1.用c語言實現。2.for中的i,j定義適用於c99標準,gcc編譯要新增 std c99選項。或者將i,j的定義放到for之前的外部作用域。3.逆運算使用了c99標準的vla,即變長陣列,只能用於區域性作用域,且宣告時不能初始化 也可以不用vla,使用malloc等...
總結 康托展開及其逆運算
這裡先貼一道例題 我們先科普一下康托展開 x an n 1 an 1 n 2 ai i 1 a2 1 a1 0 ai為整數,並且0 ai 簡單點說就是,判斷這個數在其各個數字全排列中從小到大排第幾位。比如 1 3 2,在1 2 3的全排列中排第2位。維基 n位 0 n 1 全排列後,其康托展開唯一且...
模板 康拓展開和他的逆運算
康托展開 康托展開的公式是 x an n 1 an 1 n 2 ai i 1 a2 1 a1 0 其中,ai為當前未出現的元素中是排在第幾個 從0開始 n指的是陣列的長度。舉個例子,有乙個陣列 s a b c d 它的乙個排列 s1 d b a c 則 x s1 a4 3 a3 2 a2 1 a1 ...