對於乙個集合 ,很明顯它有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、然後對調x和y的位置;
4、最後將y之後的數字全部翻轉。
例子:
比6784321大的下乙個序列是什麼?
1、首先從左往右,第乙個不按照公升序排序的數字是x=7;
2、再次從左往右,第乙個比 x 大的數字是y=8;
3、然後對調x和y,得到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...