暴力求解法中的列舉排列,生成全排列

2021-07-30 14:38:52 字數 2627 閱讀 8038

**對於乙個長度為n陣列長度的陣列=。要想列舉它的所有的長度為n的全排列出來。**

有兩種選擇:乙個是直接列舉, 另外乙個是使用遞迴來構造。

先說最容易理解的直接列舉。 例如當 n=5 的時候,我們生成的排列從小到大有 1234,1243,1324,..... ,4321。很容易地,我們可以用4個for迴圈搞定。

**如下:

#include

#include

#include

#include

using

namespace

std;

int main()

在這個演算法裡面我們用*continue*來直接跳過輸出重複的排列,避免運算不必要的解,從而降低時間複雜度。但是這個演算法有遇到 n 更大的時候就要寫 n-1個for迴圈,看過《啊哈演算法》的都知道 裡面有乙個9個for迴圈的求解。。。。。。這個就不用多說了。

繼續討論n更加大的時候的問題, 前面說了,當n等於10的時候我們不至於真的去寫9個for迴圈吧, 這時候我們可以用遞迴構造的方法來列舉。

遞迴函式: print_permutation(int n, int *a, int cur)

遞迴使用需要有判定界限,定義乙個陣列a,往a裡面放我們需要排列的元素p, 我們的判定界限則是: 當 n=cur 時 return 。

**如下:

#include

#include

#include

#include

using

namespace

std;

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

else}}

}int main()

; int n;

cin >> n;

cout

<< "0 - n-1 的全排列"

<< endl;

print_permutation(n, a, 0);

return

0;}

說明一下,在上面上我們預設了p = 是沒有重複的元素的集合,所以就直接不用傳入p陣列了。

# 現在我們更進一步地討論, 如果p[4]= 呢,這個是有多個重複的元素的集合。要是我們繼續使用遞迴構造的話,上面的放那個法就需要改進一下了。

我們需要考慮的問題如下:

當p陣列中存在重複陣列的時候,我們怎麼判斷函式已經歷遍了所有的元素,例如要生成排列 1122,a[0] = 1時,怎麼使a[1] = 1,a[2]=2, a[3]=2 ?

當p中存在重負元素是我們又怎麼避開多次使用相同元素作為跟節點展開?即 已經生成了排列以a[0] = 1為開頭的排列 1122, a[0] = 1為開頭的排列 1122 是不再允許被生成的。

對於問題1,我們可以在本次操作把p[i]插入a[cur]時候統計好p[i]在陣列a的 0 - cur-1 元素中 p[i]出現的次數 c2,和p[i] 在 陣列p中出現的個數c1。只要c1 > c2, 則p[i] 可以被繼續插入到 a中。

對於問題2, 我們事先對p陣列從小到大排序,對於本次需要最為根節點展開的元素 p[i] ,我們判斷 p[i] 是否與 p[i] 的上乙個元素相等, 如果 p[i]=p[i-1] 的話則說明,對於p[i]相同的值在上乙個同等高度的節點上已經使用過了,需要剪枝來避免重複列印。

生成可重複元素排列的**如下:

//含有可重複的元素陣列的全排列

#include

#include

#include

#include

using

namespace

std;

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

else}}

}}int main()

; int n;

cin >> n;

for(int i = 0; i < n; i++)

cin >> p[i];

sort(p, p+n);

cout

<< "可重複元素排列"

<< endl;

print_permutation(5, p, a, 0);

return

0;}

生成全排列的方法也可以用stl裡的 next_permutation() 來實現用法如下:

#include

#include

#include

#include

using

namespace

std;

int main()

; int n;

cin >> n;

for(int i = 0; i < n; i++)

cin >> p[i];

sort(p, p+n);

dowhile(next_permutation(p, p+n));

return

0;}

以上內容是個人基於對《演算法競賽入門經典第二版》暴力求解法部分章節的理解寫出來的,覺得大神們覺得有不當之處請多多指教。

暴力求解法 之 列舉排列

1 生成1 n的排列 include includeconst int n 1e3 10 int a n void print permutation int n,int a,int cur int i,j if cur n 遞迴邊界 for i 0 i 2 生成可重集的排列 上面求排列的程式只適用...

暴力求解法 之 列舉排列

1 生成1 n的排列 include includeconst int n 1e3 10 int a n void print permutation int n,int a,int cur int i,j if cur n 遞迴邊界 for i 0 i 2 生成可重集的排列 上面求排列的程式只適用...

暴力求解法 簡單列舉

在剛剛開始準備學習些演算法之前,網路上很多演算法高階攻略都會建議先從一些簡單的基本演算法著手入門,其中包括 列舉,貪心,遞迴和分治,遞推,構造,模擬 這些,正好這段時間我在看的劉汝佳的 演算法競賽入門經典 這本書中涉及了很多關於基礎的東西,對於演算法的學習和acm的訓練都很有幫助,所以我打算從 藍書...