題目:給出n個互不相同的字符, 並給定它們的相對大小順序,這樣n個字符的所有排列也會有一個順序.?現在任給一個排列,求出在它後面的第i個排列.這是一個典型的康拓展開應用,首先我們先闡述一下什麼是康拓展開。
(1)康拓展開
所謂康拓展開是指把一個整數X展開成如下形式:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!。(其中,a爲整數,並且0<=a[i]<i(1<=i<=n))
(2)應用實例
{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按從小到大排列一共6個:123 132 213 231 312 321。他們間的對應關係可由康託展開來找到。
1324是{1,2,3,4}排列數中第幾個大的數:
第一位是1小於1的數沒有,是0個 0*3! ;
第二位是3小於3的數有1和2,但1已經在第一位了,即1未出現在前面的低位當中,所以只有一個數2 1*2! ;
第三位是2小於2的數是1,但1在第一位,即1未出現在前面的低位當中,所以有0個數 0*1! ;
所以比1324小的排列有0*3!+1*2!+0*1!=2個,1324是第三個大數。
代碼實現:
- int kt(int s[],int n)//n表示該排列有n個數
- {
- int sum = 0;
- for(int i = 0; i < n; i++)
- {
- int temp = 0;
- for(int j = i + 1; j < n; j++)
- if(s[j] < s[i])
- temp ++;
- sum += f[n - 1 - i] * temp;//f[n]表示n的階乘
- }
- return sum + 1;
- }
練習:http://acm.nyist.net/JudgeOnline/problem.php?pid=139
康託展開的逆運算:
{1,2,3,4,5}的全排列已經從小到大排序,要找出第16個數:
1. 首先用16-1得到15
2. 用15去除4! 得到0餘15
3. 用15去除3! 得到2餘3
4. 用3去除2! 得到1餘1
5. 用1去除1! 得到1餘0
有0個數比它小的數是1
所以第一位是1
有2個數比它小的數是3,但1已經在之前出現過了所以是4
有1個數比它小的數是2,但1已經在之前出現過了所以是3
有1個數比它小的數是2,但1,3,4都出現過了所以是5
最後一個數只能是2
所以這個數是14352
代碼實現:
- void kt(int sum,int n)
- {
- int i, j, s[5];
- bool v[5]={0};
- sum--;
- for(i = 0;i < n; i++)
- {
- int t = sum / f[n - 1 - i];//f[n]表示n的階乘
- for(j = 0; j < n; j++)
- {
- if(!v[j])
- {
- if(t == 0) break;
- t --;
- }
- }
- s[i] = j;
- v[j] = 1;
- sum %= f[n - 1 - i];
- }
- }
練習:http://acm.nyist.net/JudgeOnline/problem.php?pid=143