CSP初赛复习-29-洪水填充-最大连通块

洪水填充 flood fill

从一个起始节点开始,把附近与其连通的节点提取出或填充成不同颜色颜色,直到封闭区域内的所有节点都被处理过为止。

是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法。

因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名

连通块

连通块(Connected Components),也称为连通分量,是图论中的一个概念。

一个无向图的连通块是指图中的一个最大子图,其中任意两个顶点之间存在一条路径

具体来说,对于一个无向图 G = (V, E),其中 V 是顶点的集合,E 是边的集合,连通块可以定义为:对于任意两个顶点 u、v ∈ V,如果存在一条路径从顶点 u 到顶点 v,那么它们属于同一个连通块。

一个连通块是一个最大子图,即一个连通块中的任意顶点都不能与图外的顶点相连

洪水填充主要是找有多少个连通块及每个连通块的大小等

二进制

如下2进制和10进制关系

例1
二进制   1  0  1  1   对应10进制 11 
位权     8  4  2  1   8+2+1=11
例2
二进制   1  1  1  1   对应10进制 15 
位权     8  4  2  1   8+4+2+1=15

二进制移位

左移

二进制   1  0  1  1   对应10进制 11 
位权     8  4  2  1   8+2+1=11
左移1位  末尾补0
二进制   1  0  1  1  0   对应10进制 22 相当于原数 * 2
位权     16  8  4  2  1  16+4+2=22

右移

二进制   1  1  1  1   对应10进制 15 
位权     8  4  2  1   8+4+2+1=15
右移一位 去除1位
二进制   1  1  1     对应10进制 7 相当于 原数/2 向下取整
位权     4  2  1   8+4+2+1=7 

例题 城堡问题 四邻域填充 最大房间

题目描述

     1   2   3   4   5   6   7  
   #############################
 1 #   |   #   |   #   |   |   #
   #####---#####---#---#####---#
 2 #   #   |   #   #   #   #   #
   #---#####---#####---#####---#
 3 #   |   |   #   #   #   #   #
   #---#########---#####---#---#
 4 #   #   |   |   |   |   #   #
   #############################
           (图 1)

   #  = Wall   
   |  = No wall
   -  = No wall

图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成m * n (m<=50,n<=50) 个方块,每个方块可以有0~4面墙

输入格式

输出格式

程序从标准输入设备读入数据。第1、2行每行1个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0<=p<=50)描述。

用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。

城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。输入的数据保证城堡至少有两个房间

样例输入

4 
7 
11 6 11 6 3 10 6 
7 9 6 13 5 15 5 
1 10 12 7 13 7 5 
13 11 10 8 10 12 13 

样例输出

5
9

大致思路

1 数据读取 西(1)北(2)东(4)南(8) 正好和二进制从右到左位权相同

2 读取对应数字后,可以看作这些数字是4位二进制组成,1表示为墙,0表示为无墙

3 每个数字可以固定有几个墙,并且确定是哪几面墙

​ 11=8+2+1 //8表示南墙 2表示北墙 1表示西墙 所以第1个房间有西北东3面墙

​ 6=4+2 //4表示东墙 2表示北墙 所以第2个房间有东和北2面墙

4 通过bfs向4个方向逐层扩展,顺序为西(1)北(2)东(4)南(8) ,这样可以使用二进制右移去掉1位,4次右移后本层扩展结束

5 求每个连通块的大小,bfs开始时初始统计变量cnt=1,每扩展一个点cnt+1,直到扩展结束

6 每个连通块都可以计算大小,最后通过打擂台找到最大的连通块

参考程序

#include <bits/stdc++.h>
using namespace std;
const int N=55;
struct Node{//结构体 
    int x, y;
    Node(){}//空构造 
    Node(int a, int b):x(a),y(b){}//使用参数a,b构造x,y 
};
int m,n,num,maxNum;//num:房间数 maxNum:房间最大格子数 
int mp[N][N];
int dir[4][2] = {{0,-1},{-1,0},{0,1},{1,0}};//0西(1)1北(2)2东(4)3南(8) 
bool vis[N][N];//vis[i][j]:第(i,j)位置是否已访问 
int bfs(int sx, int sy){//从(sx,sy)开始进行广搜,返回该房间(连通块)的格子数
    int cnt=1;//该房间的格子数 从当前格子计数
    queue<Node> que;
    vis[sx][sy]=true;
    que.push(Node(sx,sy));
    while(que.empty()==false){//0西(1)1北(2)2东(4)3南(8) 四个方向正好对应二进制位 
        Node u = que.front();//取出当前点 
        que.pop();
        int a=mp[u.x][u.y];//mp[u.x][u.y]为题解中的m值 
        for(int i=0;i<4;++i){// 
            int x=u.x+dir[i][0];//扩展x 
			int y=u.y+dir[i][1];//扩展y 
            /*
               1不出界
			   2不是墙  a%2 == 0:dir[i]表示的方向没有墙(a>>1 移位后末尾为0 说明不是墙)
			   3没走过 
            */ 
            if(x>=1&&x<=m&&y>=1&&y<=n&&a%2==0&&vis[x][y]==false){
                vis[x][y]=true;//标记走一个格子 
                que.push(Node(x, y));//当前格子放入队列 继续下一次扩展 
                cnt++;//记录走一个房间 
            }
            a>>=1;//右移位去掉末位 
        }
    }
    return cnt;
}
int main(){   
    cin>>m>>n;//m行n列 
    for(int i=1;i<=m;++i){
    	for(int j=1;j<=n;++j){//输入对应的数到数组 
    		cin>>mp[i][j];
		}
	}
        
    for(int i=1;i<=m;++i){
		for(int j=1;j<=n;++j){
            if(vis[i][j]==false){//没有标记过 开始bfs搜证 
                maxNum=max(maxNum, bfs(i, j));//更新房间最大格子数 找最大房间 
                num++;//每成功进行一次广搜,房间数(连通块数)加1 
            }
        }
	} 
    cout<<num<<endl;//输出房间数 
	cout<<maxNum;//输出最大格子数 
    return 0;
}

CSP初赛复习-29-洪水填充-FloodFill-练习题

https://www.cnblogs.com/myeln/articles/17647315.html

posted @ 2023-08-22 21:53  new-code  阅读(206)  评论(0)    收藏  举报