題目鏈接: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 的 * 的部分)
* * *
深度優先搜索(與遞歸和棧關係密切)
深度優先搜索從某個狀態開始,不斷地轉移狀態直到無法轉移,然後回退到前一步的狀態,繼續轉移到其它狀態;如此不斷重複,直到找到最終解
例如求解數獨,首先在某個格子內填入適當的數字,然後繼續在下一個格子內填入數字,如此重複。如果發現某個格子無解,就放棄前一個格子選擇的數字,改用其他可行的數字
深度優先搜索時,有時早已很明確地知道從當前狀態無論如何轉移都不會存在解。這種情況下,不再繼續搜索而直接跳過,該方法稱爲剪枝