POJ 2386——Lake Counting(DFS)

題目鏈接:http://poj.org/problem?id=2386

 

題解

#include<cstdio>
#include<stack>
using namespace std;

const int MAX_M=105,MAX_N=105;
char a[MAX_N][MAX_M];
int N,M;
//現在位置 (x,y)
void dfs(int x,int y){
	a[x][y]='.'; //將現在所在位置替換爲'.',即旱地 
    for(int dx=-1;dx<=1;dx++){ //循環遍歷連通的8個方向:上、下、左、右、左上、左下、右上、右下 
        for(int dy=-1;dy<=1;dy++){
            int nx=x+dx,ny=y+dy; //向x方向移動dx,向y方向移動dy,移動的結果爲(nx,ny)
            if(0<=nx && nx<N && 0<=ny && ny<M && a[nx][ny]=='W'){ //判斷(nx,ny)是否在園子裏,以及是否有積水
                dfs(nx, ny);
            }
        }
    }
}

//每個 W 看成"水漬",滿足八連通條件時構成積水;單獨一塊"水漬"也看成積水
int main(){
	scanf("%d%d",&N,&M);
	for(int i=0;i<N;++i){
		scanf("%s",a[i]);
	}
	int res=0;
	for(int i=0;i<N;++i){
		for(int j=0;j<M;++j){
			if(a[i][j]=='W'){ //只有檢測到水漬時才執行該函數 
				res++; //凡檢測到"水漬",res 先加一,至少這裏可以形成水坑 
				
				//從有 W 的地方開始 dfs
				//dfs 函數的作用是把該點的八連通區域變成旱地,以免後續遍歷時重複計數
				//同時通過遞歸的思想把八連通區域中,每個元素對應的八連通區域遍歷一遍,查找是否有其他"水漬"可構成積水 
				dfs(i,j);
			}
		}
	}
	printf("%d",res);
	return 0;
}

本題採用深度優先搜索

遍歷數組,從第一個 ' W ' 開始,把它對應的八連通區域中的 ' W ' 用 . ' 代替

每調用一次 dfs 函數,與初始的 ' W ' 連通的所有 ' W ' 就全都被替換成 . ',直到圖中不再存在 ' W ' 爲止,總共調用 dfs 函數的次數就是答案

8個方向對應8個狀態轉移,每個格子作爲 dfs 的參數最多調用一次,時間複雜度:O(8*n*m)=O(n*m)


八連通

*  *  *

* W *    (八連通指的就是左圖中相對 W 的 * 的部分)

*  *  *

深度優先搜索(與遞歸關係密切)

深度優先搜索從某個狀態開始,不斷地轉移狀態直到無法轉移,然後回退到前一步的狀態,繼續轉移到其它狀態;如此不斷重複,直到找到最終解

例如求解數獨,首先在某個格子內填入適當的數字,然後繼續在下一個格子內填入數字,如此重複。如果發現某個格子無解,就放棄前一個格子選擇的數字,改用其他可行的數字

深度優先搜索時,有時早已很明確地知道從當前狀態無論如何轉移都不會存在解。這種情況下,不再繼續搜索而直接跳過,該方法稱爲剪枝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章