來學演算法 #2 深度、廣度優先搜尋(1)
技術標籤:演算法
來學演算法 #2 深度、廣度優先搜尋(1)
深度、廣度優先搜尋——重要的搜尋方法
提起搜尋,我們首先想到的可能是查詞典。其實,深度、廣度優先搜尋和查詞典是一樣的。比如,我們要查詢一個成語,就需要根據一定的規則檢索這個成語。這裡的“一定的規則”可能只需要對字典中的部分元素進行檢索,但對於深度優先搜尋和廣度優先搜尋來說,它們需要對字典中的每個元素進行檢索,但從“深度”、“廣度”這兩個詞語中,我們就能體會到,它們檢索元素的順序有所不同。下面讓我們一起來看一道有趣的題目,並從中體會“深度優先”和“廣度優先”的思想。
給定一個二維陣列表示的“地圖”,陣列中的每個元素都由0-9之中的數字構成。其中,0表示“地圖”的此處為水域,1-9之間的數字表示“地圖”對應處的陸地的海拔高度。現在需要我們計算這個地圖裡有幾個“島嶼“。一個”島嶼“即這個島嶼以外的上下左右元素均為0。
中含有四個島嶼。
那麼,顯然地,我們只需要對每一個非0的點進行搜尋即可。
下面,先以深度優先搜尋為例。
我們需要注意到,如果多個非0點來自同一個島嶼,那麼如果直接對每個點進行搜尋的話,島嶼會被重複計數。所以,我們需要一個標記陣列來記錄這個點是否被搜尋過。
所以,我們會產生如下的變數定義。
int map[100][100], book[100][100];//map用以記錄地圖,book用以記錄這個點是否被搜尋過。
int m, n;//這個地圖的大小為m*n。
int mapcolor;//用塗色的方法統計島嶼數,即把同一島嶼塗上同一顏色。
int move[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};//用以記錄一個點可以搜尋的四個方向。
根據上述思路,我們可以寫出深度優先搜尋的函式。
void dfs(int x, int y)
{
int i;
int nx, ny;
for (i = 0; i < 4; i++)
{
nx = x + move[i][0];//nx、ny表示下一個待搜尋的點的座標。
ny = y + move[i][1];
if (nx >= m || ny >= n || nx < 0 || ny < 0)
{
continue;//排除不符合條件的點,即超出地圖範圍的點。
}
if (map[nx][ny] && book[nx][ny] == 0)
{//當地圖該處為陸地且未被搜尋過時,對該點附近的點進行搜尋。
book[nx][ny] = 1;//進行搜尋前,標記下一個點被搜尋過了。
dfs(nx, ny);//對下一個點進行搜尋。
}
}
}
根據我們寫出的深度優先搜尋函式,就可以寫出此題的完整程式碼了。
#include <stdio.h>
int map[100][100], book[100][100];
int m, n; int mapcolor;
int move[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
void dfs(int x, int y);
int main()
{
scanf("%d %d", &m, &n);
int i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
scanf("%1d", &map[i][j]);
}
}
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
if (map[i][j] && book[i][j] == 0)
{
book[i][j] = 1;
dfs(i, j);
mapcolor++;
}
}
}
printf("%d", mapcolor);
return 0;
}
void dfs(int x, int y)
{
int i;
int nx, ny;
for (i = 0; i < 4; i++)
{
nx = x + move[i][0];
ny = y + move[i][1];
if (nx >= m || ny >= n || nx < 0 || ny < 0)
{
continue;
}
if (map[nx][ny] && book[nx][ny] == 0)
{
book[nx][ny] = 1;
dfs(nx, ny);
}
}
}
從這道題目中,我們不難體會到深度優先搜尋是一種“一條路走到黑”的策略。如果把搜尋想象成走迷宮,那麼深度優先搜尋就是先走到一條路的盡頭,再退到上一個岔路口,選取一條沒有走過的路重複“一條路走到黑”,如果後退一步時沒有發現別的路,那就再退一步,選取沒有走過的路,直到找到符合題意的解的過程。
如果還是沒有充分理解,可以到以下網站觀看動圖演示。
https://ssthouse.github.io/visual-explain/#/list/dft