BFS與DFS演算法

2021-10-08 20:10:45 字數 3884 閱讀 9132

dfs總結

首先,我們先了解一下bfs,bfs又稱廣度優先搜尋,一般都是用於解決一些圖,樹的遍歷問題。

其實廣度優先搜尋就類似與二叉樹的層序遍歷過程,需要借助c++中stl裡面的queue佇列容器來實現這個過程。它其實就是一種分層查詢的過程,每次向前走一步,都會去訪問一批可以訪問的節點,不會存在dfs裡面的回退情況。

大致的演算法思路是這樣:

首先,需要定義乙個是否判重的陣列visited[ ]以及乙個佇列q

初始節點最先放在佇列中去,並標記判重。

執行迴圈,迴圈條件為佇列是否為空

取出佇列最上面的乙個節點,並刪除這個節點。

如果遇到目標節點,直接輸出,退出迴圈,否則的話,繼續迴圈。

分別遍歷可以訪問的節點,並判重標記。

在這裡,我們就舉乙個經典的例題來具體講解一下bfs的具體實現過程。

我們來看一下poj的3278題。

鏈結 : poj 3278

這道題的大意其實就是農夫想知道一頭牛的位置,農夫和牛都在數軸上,農夫起始點為n(0<=n<=100000),牛位於點k(0<=k<=100000),農夫有兩種移動方式。

1.從x移動到x+1或者x-1,花費一分鐘。

2.從x移動到2*x,花費一分鐘。

求解找到牛所花費的最短時間。

對於這道題,可以看出來它的目的就是找出最短時間,這其實就類似與咱們的走迷宮模型,這個其實就是bfs的經典演算法模型的應用,我們來分析一下這道題的演算法實現思路。

我們以n=3,k=5為例來分析,那麼n就為初始節點,而k則為目標節點。用佇列來處理這個擴散過程清晰易懂。

3進隊,當前佇列是{3}

3出隊,2,4,6進隊,當前佇列是{2,4,6}

2出隊,1進隊,當前佇列是{4,6,1}

4出隊,5進隊,找到目標節點,退出迴圈。

對於這道題,我們想要實時記錄到達每個節點所需要的時間,我們需要去自定義乙個結構體,可以記錄該節點的位置以及所需時間。我們直接上ac**(c++)。

#include

#include

#include

using

namespace std;

int n,k;

const

int maxn =

100000

;int visited[maxn+10]

;//判重標記,visited[i] = true表示i已經擴充套件過

struct step};

queue q;

//佇列,即open表

intmain()

else

if( s.x +

1<= maxn &&

!visited[s.x+1]

)if( s.x *

2<= maxn &&

!visited[s.x*2]

) q.

pop();

}}return0;

}

(注意: 這裡我沒有用c++的萬能標頭檔案#include的原因是:poj**本身是不支援這個標頭檔案的,但是在編譯器裡寫可以的,只不過在poj提交的時候要修改一下哈)

我這裡推薦了幾道經典的bfs演算法題,可以去寫一下。

鏈結1:hdu 1312

dfs又稱深度優先搜尋,是沿著數的深度去遍歷樹的節點,從乙個根節點出發,遍歷所有的子節點,從而得出最優解,我們其實就是用遞迴來實現的。

我們在概念中提到,用遞迴列舉出所有的路徑,這種方法顯然是不太可行的,可能會因為數量太大而超時,由於很多的子節點是不符合條件的,所以在遞迴的時候要學會「撤退」,這種方法就叫做回溯,在回溯中用於減少子節點擴充套件的函式就叫做剪枝函式

其實我們在大部分的dfs題目中,都會用到回溯的思想,難度主要在於如何在擴充套件子節點的同時,構造停止遞迴並且返回的條件。

我們首先要明確子節點符合的條件,已經放好的皇后為(i,j),新皇后節點的座標為(r,c):

(1) 橫向 i != r

(2) 縱向 j != c

(3) 斜對角 |i-r| != |j-c|

則這道題的ac**如下(帶有注釋):

#include

using

namespace std;

int n,total=0;

int col[12]

=;bool

check

(int c,

int r)

}return

true;}

void

dfs(

int r)

for(

int c=

0;c}int

main()

;for

(n=0

;n<=

10;n++

)while

(scanf

("%d"

,&n)

&&n)

return0;

}

這也是經典的回溯演算法,要在適當的地方剪枝,其實思路和前面的題目相同,無非就是記錄一下它的路徑。

class

solution

void

backtrack

(int left,

int right,

const string &s)

if(left < n && left > right)

else

if(left == n)

else

if(left == right)}}

;

我們來看一下這道題的ac**,這裡我們就運用了經典的回溯演算法

對於backtrack函式,第乙個引數代表左括號的個數,第二個引數代表右括號的個數,第三個引數代表實時的字串。

那現在我們就要討論什麼時候加左括號或者右括號啊

第一種:可以放置』(『或者』)'

條件:當 『(』 的數量大於 『)』 的數量 並且 『(』 的數量小於 n 時,即 if (left < n && left > right)。

可以思考 s = ( ( ) _ _ _ 和 s = ( ( ( ) _ _這兩種情況。

第二種:只能放置』('

條件:當 『(』 的數量等於 『)』 的數量時,我們只能向後新增 『(』 。

可以思考 s = ( ( ) ) _ _ 和 s = ( ) ( ) _ _這兩種情況。

第三種:只能放置』)'

條件:當 『(』 的數量等於 n 時,我們只能向後新增 『)』 。

可以思考 s = ( ( ( _ _ _ 和 s = ( ) ( ( _ _這兩種情況。

我們回溯的終止條件:

回溯函式中,left 和 right 代表的是 s 中左右括號的數量。

left + right == 2 * n時,回溯結束。

在具體程式設計的時候,一般用佇列這種資料結構來具體實現bfs,甚至可以說「bfs=佇列」。也可以說「dfs=遞迴」,畢竟用遞迴實現dfs是最普遍的。當然,dfs也可以用棧這種資料結構來實現,棧和遞迴在演算法思想上是一致的。

演算法 DFS與BFS

一 dfs 深度優先搜尋 dfs 深度優先遍歷dfs與樹的先序遍歷比較類似。假設初始狀態是圖中所有頂點均未被訪問,則從某個頂點v出發,首先訪問該頂點然後依次訪問它的所有鄰接結點,每次訪問乙個鄰接結點時,以該鄰接結點為根結點繼續進行dfs,直到結點的所有鄰接結點以及其鄰接結點的鄰接結點都被訪問完,才訪...

演算法(九) DFS與BFS演算法

優秀的模板 很棒的總結 具體講解可以參考 啊哈!演算法 題2045 題目描述 在乙個55的地圖上,存在著障礙物和平地。在這個地圖中,小x想要找到回家的路。地圖上,你可以每次上下左右行走一步。他希望他回家所走的是最短路,請問,他所走的路徑中,最短路的方案數。輸入共5行,每行是乙個字串。表示空地,表示障...

演算法筆記之DFS與 BFS

基本思想 深度優先搜尋 dfs,depth first search 它從某個狀態開始,不斷的轉移狀態直到無法轉移狀態,然後回退到前一步的狀態,繼續轉移到其它狀態,如此不繼重複,直至找到最終的解。寬度優先搜尋 bfs,breadth first search 總是先搜尋距離初始狀態近的狀態,也就是說...