1. 程式人生 > 其它 >來學演算法 #2 深度、廣度優先搜尋(1)

來學演算法 #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