基礎演算法 用遞迴實現列舉

2021-10-07 23:31:44 字數 2999 閱讀 3326

1~n的排列型列舉:若n=3,一種結果為:123,132,213,231,312,321

1~n的組合型列舉:若n=3,m=2,一種結果為:12,13,23

1~n的指數型列舉:若n=3,一種結果為:(空),1,12,123,2,23,3

關於有重複元素時避免重複列舉的思考

注意:

關於重複元素造成列舉結果重複如何解決會在第四個模組來講述~

本文的三種型別列舉的列舉結果要求不能重複

例題(**於acwing):

無重複元素:acwing94. 遞迴實現排列型列舉、acwing93. 遞迴實現組合型列舉、acwing92. 遞迴實現指數型列舉

有重複元素:acwing1537. 遞迴實現排列型別列舉 ii、acwing1573.遞迴實現組合型列舉 ii、acwing1572.遞迴實現指數型列舉 ii

利用dfs實現按位列舉,個數達到要求則輸出路徑結果

//資料範圍:1 ≤ n ≤ 9

#include

#include

using

namespace std;

const

int n =10;

int a[n]

, n, path[n]

;//a為待列舉的序列,n為序列元素的個數,path儲存dfs的路徑結果

bool vis[n]

;//布林陣列用來判斷在dfs過程中序列元素是否已被放入path中

void

dfs(

int u)

for(

int i =

0; i < n; i++)if

(!vis[i])}

intmain()

比起排列型列舉,組合型列舉有了個數限制,不一定要序列中所有元素都列舉出來

組合型列舉將「無視」順序的不同,元素種類及對應個數相同的兩種不同排列的列舉結果被視為相同

組合型列舉也是採用dfs的方式進行列舉,個數到達要求即輸出路徑結果

因為對順序沒有要求,所以我們可以人為讓列舉結果中的數字公升序排列,這樣確保不會因為元素的順序不同而造成列舉結果重複(但是重複元素造成的列舉結果重複無法解決)

//資料範圍:n>0, 0≤m≤n, n+(n−m)≤25, 序列內所有元素均不大於 n。

#include

#include

using

namespace std;

const

int n =30;

int a[n]

, n, m;

//a為待列舉序列,n為其長度、m為單個列舉結果長度

void

dfs(

int state,

int u,

int start)

//用乙個state來代替vis和path

for(

int i = start; i < n; i++

)//每次從起點開始列舉、確保所有結果公升序排列if(

(state >> i &1)

==0)}

intmain()

與組合型列舉一樣,列舉的結果中的元素沒有順序要求

與組合型列舉相比,指數型列舉的列舉結果長度不一定

與組合型列舉類似,也是採用dfs來列舉,所不同的是其一邊遞迴一邊輸出路徑結果

//資料範圍:1≤n≤15, 序列內所有元素均不大於 n。

#include

#include

using

namespace std;

const

int n =20;

int n, a[n]

;void

dfs(

int state,

int u,

int start)

//用乙個state來代替vis和path

}int

main()

以上三種遞迴列舉基本上都是使用dfs來實現,但是遞迴實現方式不只有dfs,還有其他的方式,不過用dfs來實現比較常見

避免重複的方法有許多種,例如將重複元素按個數分組,一次選一組放入路徑結果然後遞迴到下一層。這裡我們採取另外一種思考方式,上述三個中型別列舉都是基於這種思考方式來處理的,可見其具有一定的通用性。

問題說明:

以序列2 2的的長度為2的組合型列舉為例,若不處理重複元素造成的問題,則結果有兩種:2 2和2 2,明顯重複列舉了,造成重複的原因是重複元素的不同排列組合均放入列舉結果輸出,為了方便理解給重複元素標個號,如:2(1),2(2),剛剛的兩種列舉結果為2(1),2(2)和2(2),2(1)。如果乙個序列有n個重複元素x,對於所有包含k個x的重複列舉結果數為(忽略其他原因造成的重複):

c nk

∗k

!_n^k * k!

cnk​∗k

!解決方法:

我們可以人為規定重複元素列舉順序,所有列舉結果的值相同重複元素必須按照規定來選取(例如相連公升序,列舉後面的重複元素之前必須先列舉之前的同值重複元素,即若乙個列舉結果中還有k個重複元素x,那麼這k個x只能是x(1), x(2), …,x(k)且按位從小到大排列),否則捨棄該列舉結果(例子中的2(2),2(1)),實現方式如下(相連公升序):

將序列排序,使得所有值相同的相同元素相鄰

在dfs過程中,若有乙個元素與其在序列中的前乙個元素值相同且前乙個元素並沒有放入路徑結果path中,則直接continue剪枝(否則會造成列舉結果重複)

以上兩條只需通過兩行**實現,具體實現方式看上面的**

用遞迴列舉實現八皇后問題

include using namespace std int total 0 判斷row行line列是否可以放皇后 bool iscan int row int line int chess 8 8 判斷左上是否有皇后 for i row j line i 0 j 0 i j 判斷右上是否有皇后 ...

演算法 遞迴實現指數型列舉

從 1 n 這 n 個整數中隨機選取任意多個,輸出所有可能的選擇方案。輸入格式 輸入乙個整數n。輸出格式 每行輸出一種方案。同一行內的數必須公升序排列,相鄰兩個數用恰好1個空格隔開。對於沒有選任何數的方案,輸出空行。本題有自定義校驗器 spj 各行 不同方案 之間的順序任意。資料範圍 1 n 15 ...

用SQL語句實現遞迴演算法

本文通過乙個bom表的例子,分別介紹在sql server2000和sql server2005中如何編寫遞迴演算法。一 建立測試資料 createtablebillofmaterial productno nvarchar 15 父元件編號 productname nvarchar 50 子元件名...