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-练习题
作者:newcode 更多资源请关注纽扣编程微信公众号

从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习

浙公网安备 33010602011771号