Flood Fill算法

翻译过来就是洪水覆盖,形象的表示这个算法将地图分为凹凸两种地形,以此来判断是否联通。

 

算法过程:如果要用水覆盖,则选择一个凹点,遍历它周围四个格子,如果也是凹格子则水可以漫延过去,再遍历所有新加入的点,判断是否可以漫延,上图中的黄色点最终都可以变为蓝色。

例题:池塘计数

农夫约翰有一片 N∗M 的矩形土地。

最近,由于降雨的原因,部分土地被水淹没了。

现在用一个字符矩阵来表示他的土地。

每个单元格内,如果包含雨水,则用”W”表示,如果不含雨水,则用”.”表示。

现在,约翰想知道他的土地中形成了多少片池塘。

每组相连的积水单元格集合可以看作是一片池塘。

每个单元格视为与其上、下、左、右、左上、右上、左下、右下八个邻近单元格相连。

请你输出共有多少片池塘,即矩阵中共有多少片相连的”W”块。

输入格式

第一行包含两个整数 N 和 M。

接下来 N 行,每行包含 M 个字符,字符为”W”或”.”,用以表示矩形土地的积水状况,字符之间没有空格。

输出格式

输出一个整数,表示池塘数目。

数据范围

1 ≤ N,M ≤ 1000

输入样例:

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

注意此题与模板有一处不同:本题求的是八联通 

#include<cstring>
#include<algorithm>
#include<iostream>

#define x first
#define y second

using namespace std;

typedef pair<int,int> pii;

const int N=1010,M=N*N;

int n,m;//长宽 
char g[N][N];
pii q[M];
bool st[N][N];

void bfs(int sx,int sy)//传入起点和终点
{
	int hh=0,tt=0;//模拟队列的队首和队尾
	q[0]={sx,sy};
	st[sx][sy]=true;//标记变量
	while(hh<tt)
	{
		pii t=q[hh++];
		for(int i=t.x-1;i<=t.x+1;i++)
		for(int j=t.y-1;j<=t.y+1;j++)
		{
			if(i==t.x&&j==t.y)continue;//去掉中间
			if(i<0||i>=n||j<0||j>=m)continue;//超出范围 
			if(g[i][j]=='.'||st[i][j]) continue;
			 q[++tt]={i,j};
			 st[i][j]=true;
		 } 
	 } 
 } 
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",g[i]);
	}
	int cnt=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(g[i][j]=='W'&&!st[i][j])
			bfs(i,j);
			cnt++;
		}
	}
	printf("%d",cnt);
 } 

细节分析:

1.在遍历方格时,如果遇到池塘,会将与当前池塘联通的格子都标记,记为一个连通块,再往后搜索时,只会将没遍历过即不属于任何一个连通块的计算入

2.枚举周围格子时,有四联通和八联通等等,八联通通常就是如上,把中间格子扣掉

四联通通常是设置偏移量,如:

dx[ 4 ] = {0,-1,0,1},dy[ 4 ] = {-1,0,1,0};

for(int i = 0; i < 4;i ++)
        {
            int a = t.x + dx[i],b = t.y +  dy[i];
            if(a < 0||a >= n||b < 0||b >= m)//边界判断
            continue;
            if(st[a][b])
            continue;
            if(g[t.x][t.y]>>i&1)  continue;
            q[ ++tt] = {a,b};
            st[a][b] = true;
        }

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值