深度優先搜尋(depth first search,簡稱深搜)是一種極其常用的演算法,簡單來說,符合以下策略的就可以稱為深度優先搜尋。
在圖中行走,沒有走過的點稱為「新點」,所有走過的點稱為「舊點」。開始時所有的點都是新點,從任意節點1出發,走向任意乙個新節點,同時將新節點標記為舊節點,然後重複此步驟。如果發現不能再走到下乙個新節點,則回退到上乙個走過來的節點,重複此步驟,直至可以找到新節點為止。如果走到了目標節點,則返回true;如果直到回退到節點1還是無法找到新節點,則稱不存在節點1到目標節點的路徑。
可以用以下偽碼來表示:
bool dfs(v)
return false
}
如果僅僅要求遍歷乙個圖而不需要尋找路徑,則可以這樣改動
dfs(v)
return false
}int main()
}
如果要求需要記錄走到終點的路徑,則演算法可以簡單改動為以下
node path[max_len]; //path表示走過的路徑
int depth; //depth表示當前深度
bool dfs(v)
--depth; //無法再找到可以走的新點,回溯
return false;
}
1.鄰接表
使用vector陣列來表示每個點連線的邊,邊的資訊包含另乙個節點還可能包含邊的權值等。
優點:對於邊較為稀少的圖(大部分的圖邊都是比較稀少)可以節省空間和時間,演算法複雜度大概為o(n+e)
缺點:對於邊很稠密的圖,由於每個點都要表示,所以邊比較稠密時(e很大)反而不如鄰接矩陣的o(n^2)來的划算
2.鄰接矩陣
直接使用乙個二維陣列來表示邊,例如v[i][j]表示i節點和j節點之間的邊,一般來說值為true或false,有權值時可以寫乙個struct來加上權值
優點:對於邊很稠密的圖,由於每個點都要表示,鄰接矩陣的o(n^2)來比較划算
缺點:大部分情況下邊稀疏時比較浪費空間
總結:一般情況下都使用鄰接表,極少數情況下使用鄰接矩陣,但有時追求速度時也可以用鄰接矩陣來寫(比較方便)
其實dfs的本質也就是在圖上找路,可能是找一條/找多條,也可能是找最優解,但本質不變。很多題看起來似乎與dfs毫不相關,但其實仔細分析之後其實都可以轉化為dfs問題,不一定是題中明確指出了一幅圖才想起來用dfs,很多時候圖中的節點和狀態並沒有那麼直觀。
構成圖的結點也可以稱為狀態,一副圖也就是乙個狀態空間。起點就是初始狀態,終點就是目標狀態。乙個狀態可以通過轉移到下乙個狀態,多個狀態又對應多個狀態(廢話。一對一或者一對多還用得著dfs嗎),我們按照列舉的思想遍歷每個聯通的路就行了。所以尋找乙個狀態,用合適的語言來描述乙個狀態是最關鍵的一步。dfs不同於動態規劃,在轉移的時候並不會太過複雜。
舉兩個例子。
迷宮問題
如下圖的乙個小迷宮,像連連看一樣輸入兩座標,連線尋找兩座標的最小線段數(也就是拐了幾個彎+1)。
這個題乍一看似乎不太像dfs,但其實就是。我們來思考一下「狀態」會是什麼?首先我們需要起點終點座標x1,y2,x2,y2,然後還需要乙個方向,因為答案就是輸出方向變了幾次,再需要乙個當前步數,因為答案要求輸出最小步數。
這樣一來就成了dfs(int x1, int y1, int x2, int y2, int curentstep, int direction)
我們的初始狀態就是dfs(x1, y1, x2, y2, ∞,-1),目標狀態就是dfs(x2, y2, x2, y2, minstep,..)
而圖也就是題中所描述的,可以走到也就是聯通的,有牆就是不連通的
染色問題
染色問題經常會出現在dfs的問題中,例如城堡問題,房間問題都需要用到染色的思想,也就是把每個聯通的圖染成一種顏色,多個不連通的圖染為不同顏色。一般會要求求極大聯通子圖。
例題:poj2815 城堡問題
題解:剪枝
一般有以下幾種。
1.可行性剪枝:提前預判繼續走下去能不能走到終點,如果不能,就直接剪掉。
2.最優性剪枝:提前預判這樣走下去會不會是最優解,如果不是,就直接剪掉
具體的剪枝方案要針對每個題來看,往往很多題目如果找不出來足夠多的剪枝方案的話根本就過不去,而往往最難找到的就是最優性剪枝。
例題:poj1724 尋路問題
題解:搜尋順序
在搜尋的時候往往要講究順序,不同的順序會導致搜尋快慢的天壤之別。舉個例子來說,當你玩七巧板的時候,你是先放大的呢,還是先放小的呢?
《演算法筆記》深度優先搜尋DFS
問題 有n件物品,每件重量為w i 價值為c i 放進容量為v的揹包中。問 能放進揹包的物品的最大價值?分析 1.每件物品 選 不選,兩種狀態 迷宮的岔道口 2.超過v,邊界 迷宮的死胡同 3.到達邊界,返回最近的岔道口 4.dfs需要記錄 5.兩種轉移狀態 dfs index 1,sumw w i...
演算法筆記之深度優先搜尋 DFS
由於各種筆試 面試都有演算法程式設計題,總感覺對於演算法和資料結構比較心虛。最近開始刷一些演算法題,複習一下資料結構以及演算法的相關知識。過程中記錄一下知識點,聊勝於無。兩個問題如下 一共有10塊積木,每個積木上有乙個數字,0 9。搭積木規則 每個積木放到其它兩個積木的上面,並且一定比下面的兩個積木...
深度優先搜尋演算法(DFS)
1.深度優先搜尋屬於圖的遍歷演算法的一種,英文縮寫為dfs即depth first search.其過程簡要來說是對每乙個可能的分支路徑深入到不能再深入為止,而且每個節點只能訪問一次。2.搜尋策略 深度優先遍歷圖的方法是,從圖中某頂點v出發 1 訪問頂點v 2 依次從v的未被訪問的鄰接點出發,對圖進...