题目描述:给定一个N×M的字符矩阵,其中的元素由'W'和'.'组成,其中'W'代表有积水,'.'代表没有积水,八连通的积水可看成连在一起形成一个水洼,所谓八连通就是以当前位置为中心的八个方向,若相邻任一方向上有积水,则可以互连形成同一个水洼,问该矩阵土地上有多少个水洼?
输入描述:第一行输入正整数N和M,再输入N×M的字符矩阵
输出描述:水洼的个数
输入示例:
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
输出示例:
3
示例说明:三个水洼分别在矩阵土地的左上部分、右部分,左下部分
解题思路:(参考自《挑战程序设计竞赛》一书):这是一道经典的深度优先搜索(DFS)题,从任意的W开始,不停地把邻接的部分(八连通)用 '.' 代替。1次DFS后与初始的这个W连接的所有W就都被替换成了'.',因此直到图中不在存在W为止,总共进行DFS的次数就是答案了。8个方向的共对应了8种状态转移,每个格子作为DFS的参数至多被调用一次。
时间复杂度:O(8×M×N)=O(M×N)
coding:
#include<iostream> #include<algorithm> //注意POJ不支持<bits/stdc++.h>,老老实实写头文件 using namespace std; int N,M; //注意要定义成全局变量 char a[100][100]; //最大的field矩阵 void dfs(int i,int j) { a[i][j]='.'; //当前位置是'W',将其替换成'.' ,很容易忽视的一步 int nx,ny; //如果当前位置的邻近(八连通)有积水,则记录其坐标为(nx,ny) for(int dx=-1;dx<=1;dx++) for(int dy=-1;dy<=1;dy++) { //要搜索完八个方向,简化成两个方向,即横向和纵向 nx=i+dx; ny=j+dy; if(nx>=0 && nx<=N && ny>=0 && ny<=M && a[nx][ny]=='W') { //要确保搜索位置没有超出矩阵范围并且该位置有积水,才开辟新的搜索 dfs(nx,ny); } } } int main() { cin>>N>>M; //输入第一行 for(int i=0;i<N;i++) for(int j=0;j<M;j++) { cin>>a[i][j]; //field矩阵的建立 } int ans=0; //ponds个数,也就是DFS次数 for(int i=0;i<N;i++) for(int j=0;j<M;j++) { if(a[i][j]=='W') { dfs(i,j); ans++; } } cout<<ans<<endl; }