DFS演算法和一些例項

2021-10-03 21:50:00 字數 3406 閱讀 9803

dfs(深度優先搜尋)

深度優先搜尋演算法(英語:depth-first-search,簡稱dfs)是一種用於遍歷或搜尋樹或圖的演算法。 沿著樹的深度遍歷樹的節點,盡可能深的搜尋樹的分支。當節點v的所在邊都己被探尋過或者在搜尋時結點不滿足條件,搜尋將回溯到發現節點v的那條邊的起始節點。整個程序反覆進行直到所有節點都被訪問為止。屬於盲目搜尋,最糟糕的情況演算法時間複雜度為o(!n)。(wiki)

(直到走不下去才往回走)

基本模板

int check(引數)

void dfs(int

step)

嘗試每一種可能

}

下面來結合幾個dfs例項來理解

到底什麼是dfs ?怎麼用dfs解決問題 ?

1、全排列問題

//全排列問題

#include

#include

int n;

char a[15];

char re[15];

int vis[15];

//假設有n個字元要排列,把他們依次放到n個箱子中

//先要檢查箱子是否為空,手中還有什麼字元,把他們放進並標記。

//放完一次要恢復初始狀態,當到n+1個箱子時,一次排列已經結束

void dfs(int step)

for(i=1;i<=n;i++)//遍歷每一種情況

}return ;

}int main(void)

return

0;}

2.

乙個環由個圈組成,把自然數1,2,…,n分別放在每乙個圓內,數字的在兩個相鄰圈之和應該是乙個素數。 注意:第一圈數應始終為1。

input: n(0~20)

output:輸出格式如下所示的樣品。每一行表示在環中的一系列圓號碼從1開始順時針和按逆時針方向。編號的順序必須滿足上述要求。列印解決方案的字典順序。

//prime ring problem

//與上面的全排列問題其實思路差不多,只是需要判斷的條件比較多

//化大為小

#include

#include

#include

int book[25];

int result[25];

int n;

int num;

//判斷是否為素數

int prime(int n)

if(i*i>n)

return

1; return0;}

//判斷是否能將當前的數字放到當前的圈內

int check(int i,int step)

return

1; }

return0;}

void dfs(int step)

printf("\n");

return ;

}int i;

for(i=2;i<=n;i++)//遍歷每一種情況

}}int main(void)

return

0;}

3.油田問題

問題:geosurvcomp地質調查公司負責探測地下石油儲藏。 geosurvcomp現在在一塊矩形區域探測石油,並把這個大區域分成了很多小塊。他們通過專業裝置,來分析每個小塊中是否蘊藏石油。如果這些蘊藏石油的小方格相鄰,那麼他們被認為是同一油藏的一部分。在這塊矩形區域,可能有很多油藏。你的任務是確定有多少不同的油藏。

input: 輸入可能有多個矩形區域(即可能有多組測試)。每個矩形區域的起始行包含m和n,表示行和列的數量,1<=n,m<=100,如果m =0表示輸入的結束,接下來是n行,每行m個字元。每個字元對應乙個小方格,並且要麼是』*』,代表沒有油,要麼是』@』,表示有油。

output: 對於每乙個矩形區域,輸出油藏的數量。兩個小方格是相鄰的,當且僅當他們水平或者垂直或者對角線相鄰(即8個方向)。

//a - oil deposits 

#include

#include

#include

char a[105][105];

int n,m,result;

int dir[8][2]=,,,,,,,};//表示8個方向

int check(int x,int y)//檢查是否有油田

int dfs(int x, int y)

return

1; }

return0;}

int main(void)

}printf("%d\n",result);

}return

0;}

4、棋盤問題

問題:在乙個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請程式設計求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案c。

input: 輸入含有多組測試資料。 每組資料的第一行是兩個正整數,n k,用乙個空格隔開,表示了將在乙個n*n的矩陣內描述棋盤,以及擺放棋子的數目。 n <= 8 , k <= n 當為-1 -1時表示輸入結束。 隨後的n行描述了棋盤的形狀:每行有n個字元,其中 # 表示棋盤區域, . 表示空白區域(資料保證不出現多餘的空白行或者空白列)。

output:對於每一組資料,給出一行輸出,輸出擺放的方案數目c (資料保證c<2^31)。

#include

#include

#include

int n, k, ans;

char str[10][10];

int vis[100];

void dfs(int r, int k)

for(int i=r; i//每次都從放過棋子下一行開始搜尋,保證不重複

}}int main(void)

return

0;}

總結一下,用遞迴法來實現dfs,比較好理解,就一直往下找,知道走不通後在回來嘗試其它的地方。乙個dfs一般要判斷邊界,check來判斷是否符合相應條件,vis或者book來記錄是否已經被用過,遞迴進行下一步操作。有的時候我們要將標記過的點恢復原來的狀態,有時候則不必要恢復(油田問題),要結合具體的問題來分析。

恢復標記相當於回溯的思想。

回溯法(探索與回溯法)是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為「回溯點」。

乙個小建議:dfs理解起來不是很難,但是只理解不練習是沒有用的。一定要找一些經典的題目多加練習,只有這樣才能加深自己的理解,掌握的也更快。演算法題可能難度越來越大,但是也不能放棄,自己先學再練,對自己的思維和程式設計能力也會有一定的提公升。

DFS演算法和一些例項

dfs 深度優先搜尋 深度優先搜尋演算法 英語 depth first search,簡稱dfs 是一種用於遍歷或搜尋樹或圖的演算法。沿著樹的深度遍歷樹的節點,盡可能深的搜尋樹的分支。當節點v的所在邊都己被探尋過或者在搜尋時結點不滿足條件,搜尋將回溯到發現節點v的那條邊的起始節點。整個程序反覆進行直...

一些jQuery 例項

設定內容 text html 以及 val changehtml click function 新增新的 html 內容 向 html 元素追加內容 在 html 元素之後追加內容。before after html click function jquery 操作 css 改變 html 元素的 ...

優化的一些例項

優化使用的工具,使用loadrunner做為壓力測試工具,使用jprobe進行 剖析。1 第乙個例項。原狀況 呼叫乙個api,發現執行的時間很高,用jprobe分析,發現消耗時間最長的是把快取中的乙個樹從第三個節點進行扁平化,就是把第二個節點的子樹構造為乙個列表,不知道為什麼構造這個資料的耗時比直接...