演算法 全排列問題 字典中介法

2021-10-03 05:12:39 字數 1839 閱讀 6023

有時我們希望可以找到乙個全排列的下m個全排列,而不僅僅是下乙個,就這樣出現了字典中介法。

洛谷1088 火星人

題目描述

求排列a[1],a[2],a[3],……,a[n]之後的第m個全排列。

輸入格式

共三行。

第一行乙個正整數n(1 <= n <= 10000)。

第二行乙個正整數m(1 <= n <= 100)。

下一行是1到n這n個整數的乙個排列,用空格隔開。

輸出格式

n個整數,表示第m個全排列。每兩個相鄰的數中間用乙個空格分開。

輸入輸出樣例

輸入

531

2345

輸出

124

53

這裡對於乙個全排列我們需要乙個中介數,舉個例子假設我們要求839647521的下100個全排列,這裡我們生成其對應的中介數:8後面比8小的有7個數,3後面比3小的有2個數,9後面比9小的有6個數,6後面比6小的有4個數……mid[i]表示a[i]後面比a[i]小的數的個數,得到中介數mid = 726423210。

我們可以發現對於mid[i]最大為(n - i),因為位置i後面有(n - i)個位置,只有當後面所有數都比它小的時候mid[i] = (n - i)。這樣我們就可以發現中介數mid除去最後乙個0就是乙個遞增進製數(第i位的進製是(n - i + 1),最後一位是二進位制,因為一進製恒為0),這樣我們讓這個遞增進製數72642321加上100,就是72652011

遞增進製(72642321) + 十進位制(100)

最後得到遞增進製(72652011),這也就是下100個排列的中介數了。

這裡要加個特判:如果mid[0]大於0了,代表這個排列比排列n,(n - 1),……,1還大,那麼根本沒有這種排列,所以直接返回false就行了。

用遞增進製數再求出排列:中介數mid[i]表示第i位右側比a[i]小的數的個數,因此我們每次從1開始數(mid[i] + 1)個,這裡選過的數字不能再算在其中,那麼數到的這個數字就是a[i]的值,下面是例子。

最後算一下演算法時間複雜度:最多的有兩重迴圈,所以時間複雜度是o(n^2)。

# include

# include

# include

# include

using

namespace std;

const

int n_max =

10000

;int n, m;

int a[n_max +10]

;int mid[n_max +10]

;// mid[i]表示排列中第i位後面比a[i]小的數的個數

bool flag[n_max +10]

;// flag[i]表示新排列中數字i是否被使用

bool

permutation()

if(mid[0]

>0)

return

false

;for

(int i =

1; i <= n; i++

) flag[pos]

=true

; a[i]

= pos;

}return

true;}

intmain()

演算法 全排列問題 字典序法

求乙個排列的下乙個排列我們有暴力的n進制法,當然也就有效率較高的字典序法。洛谷1088 火星人 題目描述 求排列a 1 a 2 a 3 a n 之後的第m個全排列。輸入格式 共三行。第一行乙個正整數n 1 n 10000 第二行乙個正整數m 1 n 100 下一行是1到n這n個整數的乙個排列,用空格...

全排列演算法之字典序法

字典序演算法如下 設p是1 n的乙個全排列 p p1p2.pn p1p2.pj 1pjpj 1.pk 1pkpk 1.pn 1 從排列的右端開始,找出第乙個比右邊數字小的數字的序號j j從左端開始計算 即 j max index return index 在pj的右邊的數字中,找出所有比pj大的數中...

全排列之字典序法

1 對於輸入的字典序排列,反向查詢第一對滿足a j 2 仍舊反向查詢第乙個下標k,使得 a j 3 交換a j 和a k 4 翻轉a j 1 a end 此法能適應有重複元素的系列 如下 include include using namespace std int cmp const void a...