康拓展開 & 逆康拓展開

題目:給出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的數有12,但1已經在第一位了,即1未出現在前面的低位當中,所以只有一個數2 1*2! 

  第三位是2小於2的數是1,但1在第一位,即1未出現在前面的低位當中,所以有0個數 0*1! 

  所以比1324小的排列有0*3!+1*2!+0*1!=2個,1324是第三個大數。

代碼實現:

[cpp] view plain copy
  1. int kt(int s[],int n)//n表示該排列有n個數  
  2. {  
  3.     int sum = 0;  
  4.     for(int i = 0; i < n; i++)  
  5.     {  
  6.         int temp = 0;  
  7.         for(int j = i + 1; j < n; j++)  
  8.           if(s[j] < s[i])  
  9.              temp ++;  
  10.         sum += f[n - 1 - i] * temp;//f[n]表示n的階乘  
  11.     }  
  12.     return sum + 1;  
  13. }  

練習:http://acm.nyist.net/JudgeOnline/problem.php?pid=139



康託展開的逆運算:

{1,2,3,4,5}的全排列已經從小到大排序,要找出第16個數:

1. 首先用16-1得到15

2. 15去除4! 得到015

3. 15去除3! 得到23

4. 3去除2! 得到11

5. 1去除1! 得到10

有0個數比它小的數是1

所以第一位是1

有2個數比它小的數是3,但1已經在之前出現過了所以是4

有1個數比它小的數是2,但1已經在之前出現過了所以是3

有1個數比它小的數是2,但1,3,4都出現過了所以是5

最後一個數只能是2

所以這個數是14352

代碼實現:

[cpp] view plain copy
  1. void kt(int sum,int n)  
  2. {  
  3.     int i, j, s[5];  
  4.     bool v[5]={0};  
  5.     sum--;  
  6.     for(i = 0;i < n; i++)  
  7.     {  
  8.         int t = sum / f[n - 1 - i];//f[n]表示n的階乘  
  9.         for(j = 0; j < n; j++)  
  10.         {  
  11.             if(!v[j])  
  12.             {  
  13.                 if(t == 0) break;  
  14.                 t --;  
  15.             }  
  16.         }  
  17.         s[i] = j;  
  18.         v[j] = 1;  
  19.         sum %= f[n - 1 - i];  
  20.     }  
  21. }  


練習:http://acm.nyist.net/JudgeOnline/problem.php?pid=143
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章