窮舉之排列

2021-08-10 17:18:31 字數 1668 閱讀 7923

基本思路:用陣列a來儲存排列結果,基本思想是遞迴地向陣列a[cur]中放元素p[i],直到cur==n時到達遞迴的邊界從而輸出結果。進行遞迴的條件是新放入的元素未在陣列a中,此條件是為了避免重複放入元素。由於序列p裡的元素是從1開始的連續正整數,本身是按字典序排列的,所以當從左至右地從序列p裡取元素,可以滿足最後排列的結果就是按字典序排列的。具體的遞迴過程見下圖。

上圖是乙個樹,樹葉為解,即乙個排列。從左至右,解按字典序出現。此樹展示了逐步生成完整解的過程,這個過程具有橫向迴圈,縱向遞迴的特點。橫向迴圈表示每一步有多種選擇,縱向遞迴表示每一步操作相似可以由遞迴來實現。具有這樣特點的樹叫解答樹。解答樹的結點數幾乎全部由最後兩層的結點數貢獻,上面的結點數可忽略不計。此解答樹的實現程式對應於程式1。

//程式1:

void rank_all(int n,int* a,int cur)

,此序列全排列只有一種情況,也就是序列p本身。因此序列p裡有重複元素時,可以分別統計取到的新元素p[i]在已排列的陣列a中的個數c1,以及p[i]在序列p裡的總的個數c2,這樣需要遞迴的條件就是c1小於c2。同樣p需要先按字典序排序,這樣重複的元素就相鄰了,在每次排列時重複元素不能重複作為排列頭,只需新增p[i]!=p[i-1]這個條件。具體見程式3。主函式呼叫見主程式1。

//程式3:

void rank_all(int n,int* p,int* a,int cur)

; memset(a,0,sizeof(a));

rank_all(n,p,a,0);

return 0;

}

基於dfs遞迴遍歷的思想:假設序列p中的元素已按字典序排序。從左至右依次以元素p[i]為排頭,遞迴地從左至右訪問序列p[j],只要p[j]之前沒有被訪問,即visit[j]==0就將p[j]加入到解中,result=[result p[j]]。直到p中的元素都被訪問了,乙個排列也就生成了。具體見程式4。具體呼叫程式見主程式2。

//程式4:

void rank_dfs(const vector& p,int i,int *visit,string result);

int visit[n+1];

memset(visit,0,sizeof(visit));

for(int i=0;i

借助庫函式對具有互異元素和有重複元素的序列p均可以使用

使用演算法庫

中的下乙個排列函式next_permutation()來生成下乙個排列,重複呼叫該函式就可以全部舉出來所有的排列了,並且next_permutation()也適用於有重複元素的排列。

//程式5:

//呼叫庫函式 next_permutation()來生成下乙個排列,不斷重複呼叫

#include #include using namespace std;

void rank_all(int *a,int n)

{ do{

for(int i=0;i

參考:《演算法競賽入門經典第二版》第七章。

NWPU演算法考試複習 窮舉所有排列

描述 輸入乙個小於10的正整數n,按把每個元素都交換到最前面一次的方法,輸出前n個小寫字母的所有排列。輸入輸入乙個小於10的正整數n。輸出按把每個元素都交換到最前面一次的方法,輸出前n個小寫字母的所有排列。輸入樣例 3輸出樣例 abcacb bacbca cbacab include 這題也是乙個簡...

演算法之暴力列舉(窮舉)

列舉法的基本思想是根據題目的部分條件確定答案的大致範圍,並在次範圍內對所有可能的情況逐一驗證,直到全部情況驗證完畢。若某個情況驗證符合題目的全部條件,則為本問題的乙個解 若全部情況驗證後都不符合題目的全部條件,則本題無解。也稱為窮舉法。題目 某人有n袋金幣,其中第i袋內金幣的數量是ai。現在他決定選...

演算法實驗一 遞迴分治法 窮舉所有排列

時限 100ms 記憶體限制 10000k 總時限 300ms 描述輸入乙個小於10的正整數n,按把每個元素都交換到最前面一次的方法,輸出前n個小寫字母的所有排列。輸入輸入乙個小於10的正整數n。輸出按把每個元素都交換到最前面一次的方法,輸出前n個小寫字母的所有排列。輸入樣例 輸出樣例 abcacb...