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 种朝向,如下图所示:

 starry-1.gif

现在,我们用一个二维 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

样例解释

样例对应的星空图如下:

 starry-2.gif

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

 starry-3.gif

这个题就是把一个联通块和形状相同的连通块标记成相同的字母。

这个问题的关键就是求这个哈希值。这个求法其实就是求联通块中任意两个点的欧几里得距离之和,然后哈希成为一个值

 

#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;
    }
}

 

posted @ 2021-06-15 00:54  lipu123  阅读(743)  评论(0)    收藏  举报