DFS(深度優先搜尋),BFS(廣度優先搜尋)小總結
阿新 • • 發佈:2018-12-26
這周正在學習DFS和BFS。
體驗中覺得這兩個演算法還是挺好用的,但是遇到某些資料大的情況就很容易超時。(所以到後面還是得學習一下如何優化,或者採用更佳的搜尋方法來解決問題)
然後學習了一段時間,感覺基本上了解了DFS和BFS的基礎實現原理以及應用(不過我認為還是得通過做題來培養自己的感覺,什麼時候該採取DFS,什麼時候該採用BFS),它們兩者間各自的優勢需要通過實際的問題來具體分析,根據它們各自的特點來應用於不同的問題中才能獲得最優的效能。
總的來說,兩者都是搜尋方法 (這不是廢話嘛!) ,但是兩者的搜尋方式卻有極大的區別。
我將DFS比作莽夫,就是一條路莽下去,如果有分支路,就選擇其中一條走下去,直到走到終點或者該點處沒有路可以走了,這時候只能回頭,走之前沒有走過的分支,繼續莽下去。
而BFS更像是水流。我們在最上層倒水下來,水會流向這個節點處的各個分支,逐層地開始搜尋。
由於DFS的特性,我們會採用 遞迴的方式來實現。
具體模板:
void dfs()//引數用來表示狀態,例如臨界條件,達到終點的條件
{
if(到達終點狀態)
{
...//根據題意新增
return;
}
if(越界或者是不合法狀態)
return;
if(特殊狀態)//剪枝(避免搜尋不必要的地方)
return ;
for(擴充套件方式)
{
if(擴充套件方式所達到狀態合法)
{
修改操作; //根據題意來新增
tag標記;
dfs();
還原tag標記; // dfs很重要一點就是可能要採用回溯思想,視題目而定
}
}
}
例題: HDU 1241 油田問題
AC程式碼如下:
#include <iostream>
using namespace std;
const int maxn=1e3;
char a[maxn][maxn]; // 用來儲存油田矩陣
int dir[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1, 1},{-1,1},{1,-1},{-1,-1} }; //八個方向
int m,n; //m是行 n是列
void dfs(int x,int y)
{
int tx,ty;
for(int i=0;i<8;i++)
{
tx=x+dir[i][0]; //tx,ty分別是 下一個座標代表的x,y;
ty=y+dir[i][1];
if( tx>=0 && tx<=m && ty>=0 && ty<=n ) //說明沒有越界那麼就繼續搜下去
{
if(a[tx][ty]=='@') //使@變成*
{
a[tx][ty]='*';
dfs(tx,ty); //繼續dfs深搜
}
}
}
}
int main()
{
while( cin>> m >> n && m && n )
{
for(int i=0;i<m;i++)
cin>>a[i];
int sum=0;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
if(a[i][j]=='@') //如果遍歷到一個@ 說明找到一個油田塊
{
a[i][j]='*';
sum++;
dfs(i,j); //消除油田
}
}
cout<<sum<<endl;
}
return 0;
}
BFS 基本實現就採用 佇列的方式
queue< pos > q;
// pos是一個struct 帶有 x,y座標 (用來表示二維陣列的下標)
q.push(首節點);
while(!q.empty())
{
pos temp=q.front();
q.pop();
isok[temp.x][temp.y]=true; //標記該點已經走過了
for(int i=0;i<4;i++)
{
int tx=temp.x+dir[i][0];
int ty=temp.y+dir[i][1];
if( tx < n && tx>=0 && ty >=0 && ty < m && !isok[tx][ty] && s[tx][ty]=='.')
{
isok[tx][ty]=!isok[tx][ty]; //標記該點已經走過了
q.push(pos(temp.x+dir[i][0],temp.y+dir[i][1])); // 將這個節點下的子節點插入至佇列中。
}
}