深度優先搜索算法(英語:Depth-First-Search,DFS)是一種用於遍歷或搜索樹或圖的算法。沿着樹的深度遍歷樹的節點,儘量深的搜索樹的分支。當節點v的所在邊都己被探尋過,搜索將回溯到發現節點v的那條邊的起始節點。這一過程一直進行到已發現從源節點可達的全部節點爲止。若是還存在未被發現的節點,則選擇其中一個做爲源節點並重復以上過程,整個進程反覆進行直到全部節點都被訪問爲止。屬於盲目搜索。node
深度優先搜索是圖論中的經典算法,利用深度優先搜索算法能夠產生目標圖的相應拓撲排序表,利用拓撲排序表能夠方便的解決不少相關的圖論問題,如最大路徑問題等等。ios
有n件物品,每件物品的重量爲w[i],價值爲c[i]。如今須要選出若干件物品放入一個容量爲V的揹包中,使得在選入揹包的物品重量和不超過容量V的前提下,讓揹包中物品的價值之和最大,求最大價值。(1≤n≤20)算法
若是使用DFS算法思想來解決這道題,就須要考慮到每個物品均可以看做一個結點,而這道題能夠構成一個特殊的數(從根節點開始,每一層只有一個結點),經過遞歸深度遍歷每個結點,而後窮盡全部可能的排列,最後更新某一個特徵值。函數
C++語言實現:優化
#include<iostream> using namespace std; #define maxn 30 int n,v; int maxvalue=0; int w[maxn], c[maxn]; /* 函數會一直遞歸調用下去,只要index沒有到達n,若是到達n,則說明全部物品的岔路都已經窮舉完了 每次新添加一個物品,都會生成新的岔路,每一個岔路有兩個選擇,便是否將當前物品添加到揹包 遞歸結束,會有2^n個方案,其中知足總容量<v且價值超出歷史最大價值時,更新當前最大價值 */ void dfs(int index,int sumv,int sumvalue) { //遞歸終止條件 if(index == n) { if(sumv<=v&&sumvalue>maxvalue) { maxvalue = sumvalue; } return ; } dfs(index+1,sumv,sumvalue); dfs(index+1,sumv+w[index],sumvalue+c[index]); } /* 對上面的實現進行"剪枝"優化,即每次進行岔路選擇的時候,若是添加當前物品到揹包中會超出容量v 則不添加該物品 通過優化之後,全部的岔路方案都是總容量不超出v的方案 */ void dfs2(int index,int sumv,int sumvalue) { if(index == n) { if(sumvalue>maxvalue) { maxvalue = sumvalue; } return ; } dfs(index+1,sumv,sumvalue); if(sumv+w[index]<=v) dfs(index+1,sumv+w[index],sumvalue+c[index]); } int main() { scanf("%d%d",&n,&v); for(int i =0; i<n; i++) { scanf("%d",&w[i]); } for(int i =0; i<n; i++) { scanf("%d",&c[i]); } dfs(0,0,0); printf("最大價值爲:%d",maxvalue); return 0; }
Input:spa
5 8 3 5 1 2 2 4 5 2 1 3
Output:code
最大價值爲:10
待更新排序
廣度優先搜索算法(英語:Breadth-First-Search,縮寫爲BFS),又譯做寬度優先搜索,或橫向優先搜索,是一種圖形搜索算法。簡單的說,BFS是從根節點開始,沿着樹的寬度遍歷樹的節點。若是全部節點均被訪問,則算法停止。遞歸
給出一個m*n的矩陣,矩陣中的元素爲0或1。稱位置(x,y)與其上下左右四個位置(x,y+1)、(x,y-1)、(x+1,y)、(x-1,y)是相鄰的。若是矩陣中有若干個1是相鄰的(沒必要兩兩相鄰),那麼稱這些1構成了一個「塊」。求給定的矩陣中「塊」的個數。
0111001
0010000
0000100
0001110
1110100
1111000隊列
例如上面的6×7的矩陣中,「塊」的個數爲4。
#include<iostream> #include<queue> using namespace std; const int maxn = 100; int m,n; struct node { int x,y; }; int matrix[maxn][maxn]; bool inq[maxn][maxn] = {false}; int X[4] = {0,0,1,-1}; int Y[4] = {1,-1,0,0}; bool judge(int x,int y) { if(x>=m||x<0||y>=n||y<0) return false; if(matrix[x][y]==0||inq[x][y]==true) return false; return true; } void bfs(int x,int y) { queue<node> Q; node Node; Node.x = x,Node.y = y; Q.push(Node); while(!Q.empty()) { node tmp = Q.front(); Q.pop(); //標記該位置相鄰的位置 for(int i =0; i<4; i++) { int newx = tmp.x+X[i]; int newy = tmp.y+Y[i]; if(judge(newx,newy)) { node newnode ; newnode.x=newx; newnode.y=newy; Q.push(newnode); inq[newx][newy] = true; } } } } int main() { scanf("%d%d",&m,&n); for(int i =0;i<m;i++){ for(int j=0;j<n;j++){ scanf("%d",&matrix[i][j]); } } int ans = 0; for(int i =0;i<m;i++){ for(int j=0;j<n;j++){ if(matrix[i][j]==1&&inq[i][j]==false){ ans++; inq[i][j]=true; bfs(i,j); } } } printf("%d",ans); return 0; }
Input:
6 7 0 1 1 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 1 1 1 0 1 0 0 1 1 1 1 0 0 0
Output:
4
給定一個n*m
大小的迷宮,其中*
表明不可經過的牆壁,而「.」表明平地,S表示起點,T表明終點。移動過程當中,每次只能前往上下左右四個位置的平地。求從起點S到達終點T的最少步數。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 100; struct node { int x,y; int step; } S,T,Node; int n,m; char maze[maxn][maxn]; bool inq[maxn][maxn] = {false}; int X[4] = {0,0,1,-1}; int Y[4] = {1,-1,0,0}; bool test(int x,int y) { if(x>= n||x<0||y>= m||y<0) return false; if(maze[x][y] == '*') return false; if(inq[x][y] == true) return false; return true; } int BFS() { queue<node> q; q.push(S); while(!q.empty()) { node top = q.front(); q.pop(); if(top.x ==T.x&& top.y ==T.y) { return top.step; } for(int i=0; i<4; i++) { int newx = top.x +X[i]; int newy = top.y +Y[i]; if(test(newx,newy)) { Node.x = newx,Node.y = newy; Node.step = top.step+1; q.push(Node); inq[newx][newy] = true; } } } return -1; } int main() { scanf("%d%d",&n,&m); for(int i=0; i<n; i++) { getchar(); for(int j=0; j<m; j++) { maze[i][j] = getchar(); } maze[i][m+1] = '\0'; } scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y); S.step = 0; printf("%d",BFS()); return 0; }
Input:
5 5 ..... .*.*. .*S*. .***. ...T* 2 2 4 3
Output:
11
經過對上面的例題以及代碼實現,不難發現,DFS就是結合遞歸來實現,在寫代碼的時候,須要考慮如何把問題抽象成能夠遞歸的場景,而後根據題目的要求分析出遞歸終止條件,以及傳遞公式
BFS,須要結合隊列來實現,每次都是先遍歷同一個層次的全部結點(抽象表示),而後根據順序依次加入隊列,每次循環的時候,判斷隊列是否爲空,若是不爲空再把隊列頭結點取出,而後再把這個頭節點對應的全部子節點按照順序依次加入隊列,一直到全部的結點都入隊列。一般須要一個輔助容器來記錄結點是否入過隊列。
參考資料:
https://zh.wikipedia.org/zh-hans/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2
https://zh.wikipedia.org/zh/%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2
《算法筆記》第8章提升篇——搜索專題
本文待更新,目前只涉及到算法思想以及簡單應用,後期繼續補充兩個算法思想在樹和圖中的應用