全排列的編碼與解碼 康托展開

2021-08-08 15:29:24 字數 2068 閱讀 8702

對於乙個集合 ,很明顯它有n!種全排列,

把它們全都按照字典序排好序(從小到大),對應順序,

假如問你第x個全排列是什麼,或者某個全排列在其中的序號是多少,可以利用康拓展開式來求。

康托展開式:

x = a[n]*(n-1)! + a[n-1]*(n-2)! + … + a[i]*(i-1)! + … + a[2]*1! + a[1]*0!

康托展開可以實現按字典序排序的序列自然數之間相互對應的雙射。

給出乙個全排列數字,求出這個數是第幾個全排列。

規則:

例子:

集合,按照字典序排好它的全排列,問 45231 這個數字在排列中的序號是多少?

1、比數字4小的數有3個;

2、比數字5小的數有4個,但是4已經出現在前面了,所以只有3個;

3、比數字2小的數有1個;

4、比數字3小的數有2個,但是2已經出現在前面了,所以只有1個;

5、比數字1小的數有0個;

因此 x = 3*4! + 3*3! + 1*2! + 1*1! + 0*0!

= 72 + 18 + 2 + 1 +0

= 93

給出乙個序號y,求出對應這個序號的全排列是什麼數字。

規則:

解碼是編碼的逆運算,假如這個數字的序號是y,那麼比它小的數就有x=y-1個,然後分別求出每個位置的數字是多少。

例子:

集合,按照字典序排好它的全排列,問第94個全排列是什麼數?

首先 x = 94 - 1 = 93

1、93 / 4! = 3,餘21。有3個數比它小的數字是4,所以排在第5位的數字是4;

2、21 / 3! = 3,餘 3 。有3個數比它小的數字是4,但4已經有了,因此排在第4位的數字是5;

3、 3 / 2! = 1,餘 1 。有1個數比它小的數字是2,所以排在第3位的數字是2;

4、 1 / 1! = 1,餘 0 。有1個數比它小的數字是2,但2已經有了,因此排在第2位的數字是3;

5、 0 / 0! = 0,餘 0 。有0個數比它小的數字是1,所以排在第1位的數字是1;

所以排在第94位的全排列是 45231 。

next_permutaion函式是用來求比當前排列按字典序大的下乙個序列。

規則:

1、首先從右往左遍歷陣列,找到從右開始第乙個不按照公升序排序的數字,記為x

2、再次從右往左遍歷陣列,找到第乙個比x大的數字,記為y

3、然後對調xy的位置;

4、最後將y之後的數字全部翻轉。

例子:

6784321大的下乙個序列是什麼?

1、首先從左往右,第乙個不按照公升序排序的數字是x=7

2、再次從左往右,第乙個比 x 大的數字是y=8

3、然後對調xy,得到6874321

4、最後將 y 之後的數字全部翻轉,得到6812347

所以6812347就是6784321的下乙個序列。

參考:

全排列的編碼與解碼 康托展開

康托展開 全排列到乙個自然數的雙射 x an n 1 an 1 n 2 ai i 1 a2 1 a1 0 ai為整數,並且0 ai適用範圍 沒有重複元素的全排列 二 全排列的編碼 的排列總共有n 種,將它們從小到大排序,怎樣知道其中一種排列是有序序列中的第幾個?如 按從小到大排列一共6個 123 1...

全排列的編碼與解碼 康托展開

康托展開是乙個全排列到乙個自然數的對映,可以快速求出乙個全排列在所有全排列中字典序排第幾 large x a n n 1 a n 2 a 1 0 其中 a i 表示全排列中後i個元素,第n i 1個元素排第幾 然後要減一 a i i 1 表示所有全排列中前n i個元素與當前全排列相同,且第n i 1...

康托展開 全排列

今天找到了一篇非常好的介紹康托展開的文章!其核心是這一張圖 letter 儲存所需字母表 void initletter 初始化字母表 int fact int n 階乘 return result void output vector v 輸出生成的結果 cout endl void divisi...