FloodFill算法(连通块问题)
这个好像就是解决连通块的一类的问题
例一:
农夫约翰有一片 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<bits/stdc++.h> using namespace std; int n,m,ans,a[1010][1010]; char Map[1010][1010]; int dx[8]={1,0,-1,0,1,-1,1,-1},dy[8]={0,1,0,-1,1,-1,-1,1};//方向数组 void dfs(int x,int y) { Map[x][y]='.'; for(int i=0;i<8;i++) if(Map[x+dx[i]][y+dy[i]]=='W') dfs(x+dx[i],y+dy[i]); } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>Map[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(Map[i][j]=='W'){//找到“ W ”. dfs(i,j); ans++;//统计答案 } printf("%d\n",ans); return 0; }
floodfill变形,就是统计连通块的数量和形状,这个是用的哈希,就是把一个图像哈希成为一个数
夜空深处,闪亮的星星以星群的形式出现在人们眼中,形态万千。一个星群是指一组非空的在水平,垂直或对角线方向相邻的星星的集合。一个星群不能是一个更大星群的一部分。星群可能是相似的。如果两个星群的形状、包含星星的数目相同,那么无论它们的朝向如何,都认为它们是相似的。通常星群可能有 8 种朝向,如下图所示:

现在,我们用一个二维 01 矩阵来表示夜空,如果一个位置上的数字是 1,那么说明这个位置上有一个星星,否则这个位置上的数字应该是 0。
给定一个夜空二维矩阵,请你将其中的所有星群用小写字母进行标记,标记时相似星群用同一字母,不相似星群用不同字母。
标注星群就是指将星群中所有的 1 替换为小写字母。
输入格式
第一行包含一个整数 W,表示矩阵宽度。
第二行包含一个整数 H,表示矩阵高度。
接下来 H 行,每行包含一个长度为 W 的 01 序列,用来描述整个夜空矩阵。
输出格式
输出标记完所有星群后的二维矩阵。
用小写字母标记星群的方法很多,我们将整个输出读取为一个字符串,能够使得这个字符串字典序最小的标记方式,就是我们想要的标记方式。
输出这个标记方式标出的最终二维矩阵。
数据范围
0≤W,H≤100,
0≤ 星群数量 ≤500,
0≤ 不相似星群数量 ≤26,
1≤ 星群中星星的数量 ≤160
输入样例:
23
15
10001000000000010000000
01111100011111000101101
01000000010001000111111
00000000010101000101111
00000111010001000000000
00001001011111000000000
10000001000000000000000
00101000000111110010000
00001000000100010011111
00000001110101010100010
00000100110100010000000
00010001110111110000000
00100001110000000100000
00001000100001000100101
00000001110001000111000
输出样例:
a000a0000000000b0000000
0aaaaa000ccccc000d0dd0d
0a0000000c000c000dddddd
000000000c0b0c000d0dddd
00000eee0c000c000000000
0000e00e0ccccc000000000
b000000e000000000000000
00b0f000000ccccc00a0000
0000f000000c000c00aaaaa
0000000ddd0c0b0c0a000a0
00000b00dd0c000c0000000
000g000ddd0ccccc0000000
00g0000ddd0000000e00000
0000b000d0000f000e00e0b
0000000ddd000f000eee000
样例解释
样例对应的星空图如下:

答案对应的标记后星空图如下:

这个题就是把一个联通块和形状相同的连通块标记成相同的字母。
这个问题的关键就是求这个哈希值。这个求法其实就是求联通块中任意两个点的欧几里得距离之和,然后哈希成为一个值
#include<iostream> #include<cmath> #include<algorithm> #include<cstring> #define x first #define y second using namespace std; const int maxn=1e3+100; const double esp=1e-8; typedef pair<int,int> PII; int dx[8] = {-1, -1, -1, 0, 1, 1, 1, 0}; int dy[8] = {-1, 0, 1, 1, 1, 0, -1, -1}; char g[maxn][maxn]; PII p[maxn*maxn]; double h[maxn]; int m,n; int id; int top; void dfs(int x,int y){ p[top++]={x,y}; g[x][y]='0'; for(int i=0;i<8;i++){ int xx=x+dx[i]; int yy=y+dy[i]; if(xx>=0&&xx<n&&yy>=0&&yy<m&&g[xx][yy]=='1'){ dfs(xx,yy); } } } double get_dist(PII a,PII b){ double xx=a.x-b.x; double yy=a.y-b.y; return sqrt(xx*xx+yy*yy); } double get_hash(){ double ans=0; for(int i=0;i<top;i++){ for(int j=i+1;j<top;j++){ ans+=get_dist(p[i],p[j]); } } return ans; } char get_id(double key){ for(int i=0;i<id;i++){ if(fabs(h[i]-key)<esp){ return i+'a'; } } h[id++]=key; return id-1+'a'; } int main(){ cin>>m>>n; for(int i=0;i<n;i++){ cin>>g[i]; } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(g[i][j]=='1'){ top=0; dfs(i,j); char z=get_id(get_hash()); for(int k=0;k<top;k++){ g[p[k].x][p[k].y]=z; } } } } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cout<<g[i][j]; } cout<<endl; } }

浙公网安备 33010602011771号