ch2(搜索与图论)——flood fill

1.自然语言描述
面对一个二维平面图,图中元素有不同的种类,问题要求出图中所有某一种类的元素构成了多少连通块?最大连通块的大小是多少?或是满足特殊要求的连通块有多少个?……这些问题,他们的输入数据规模往往不大;绕不开连通块这个话题。

Flood fill算法能够求出图中要求的连通块:模拟用水(想象一下Minecraft中岩浆桶和水桶的作用效果)灌满一个连通块;灌满图中所有连通块的次数就是连通块的个数。Flood fill算法在遍历连通块时采用的是BFS策略。

2.代码描述
题目:Acwing 1097.池塘计数 题目链接

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;
typedef pair<int,int> PII;

const int MAXN=1010;

int n,m;
char s[MAXN][MAXN];
bool st[MAXN][MAXN];

//flood fill是一种基于BFS的算法,它通过对每一个状态进行BFS,从而找到与当前点连通的连通分量,进而找到所有连通分量
//像洪水从一个点灌入,看它最多能漫到哪些点

void bfs(int sx,int sy)
{
    
    
    queue<PII> q;
    q.push({
    
    sx,sy});
    st[sx][sy]=true;
    
    while(!q.empty()){
    
    
        PII t=q.front();
        q.pop();
        
        for(int i=t.x-1;i<=t.x+1;i++)
            for(int j=t.y-1;j<=t.y+1;j++){
    
    
                if(i<0||i>=n|j<0||j>=m) continue;
                if(!st[i][j]&&s[i][j]=='W'){
    
    
                    q.push({
    
    i,j});
                    st[i][j]=true;
                }
            }
    }
}

int main(void)
{
    
    
    cin>>n>>m;
    
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>s[i][j];
            
    int ans=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(!st[i][j]&&s[i][j]=='W'){
    
    
                bfs(i,j);
                ans++;
            }
            
    cout<<ans<<endl;
    
    return 0;
}

题目:Acwing 1098.城堡问题 题目链接

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<int,int> PII;
const int MAXN=55;

int n,m;
int dx[]={
    
    0,-1,0,1},dy[]={
    
    -1,0,1,0};
int g[MAXN][MAXN];
bool st[MAXN][MAXN];

int bfs(int sx,int sy)
{
    
    
    queue<PII> q;
    q.push({
    
    sx,sy});
    
    int area=0;
    while(!q.empty()){
    
    
        
        PII t=q.front();
        q.pop();
        
        int x=t.first,y=t.second;
        if(st[x][y]) continue;
        st[x][y]=true;
        
        area++;
        
        for(int i=0;i<4;i++){
    
    
            int nx=x+dx[i],ny=y+dy[i];
            if(!st[nx][ny]&&!(g[x][y]>>i&1))
                q.push({
    
    nx,ny});
        }
        
    }
    return area;
}

int main(void)
{
    
    
    cin>>n>>m;
    
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>g[i][j];
        
    int ans=0,cnt=0;    
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(!st[i][j]){
    
    
                cnt++;
                ans=max(ans,bfs(i,j));
            }
            
    cout<<cnt<<endl<<ans<<endl;
    
    return 0;
}

题目:Acwing 1106.山峰问题 题目链接

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<int,int> PII;
const int MAXN=1010;

int g[MAXN][MAXN];
bool st[MAXN][MAXN];
int n;

void bfs(int sx,int sy,bool &has_h,bool &has_l)
{
    
    
    queue<PII> q;
    q.push({
    
    sx,sy});
    
    while(!q.empty()){
    
    
        
        PII t=q.front();
        q.pop();
        
        int x=t.first,y=t.second;
        
        if(st[x][y]) continue;
        st[x][y]=true;
        
        for(int i=x-1;i<=x+1;i++)
            for(int j=y-1;j<=y+1;j++){
    
    
                if(i<0||i>=n||j<0||j>=n) continue;
                if(g[i][j]!=g[x][y]){
    
    
                    if(g[i][j]>g[x][y]) has_h=true;//发现比当前山脉高的山
                    else has_l=true;
                }else if(!st[i][j])
                    q.push({
    
    i,j});
            }
        
    }
}

int main(void)
{
    
    
    cin>>n;
    
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>g[i][j];
          
    int peak,valley;
    peak=valley=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(!st[i][j]){
    
    
                bool has_h,has_l;
                has_h=has_l=false;
                
                bfs(i,j,has_h,has_l);//沿着当前山脉遍历
                
                if(!has_h) peak++;//没有比当前山脉更高的山,所以当前山脉为山峰
                if(!has_l) valley++;//反之则为山谷
            }
            
    cout<<peak<<' '<<valley<<endl;
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43579980/article/details/108930600