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 總是先搜尋距離初始狀態近的狀態,也就是說...