搜索:Flood Fill

目录

经典模板题:

1、池塘数量

2、城堡问题

3、山峰和山谷


模型:Floof Fill指洪水覆盖算法他,通常对在图中需要找到一片区域的连通块,用最简单的例子,例如求图中的连通块数量。

如何实现?

实现方式为对图中的每一个点进行bfs或者是dfs,但是这里不是遍历到每一个点都可以走的。在前面已经遍历过的点中的dfs会遍历掉所有符合条件的点,这个时候可能当前遍历到的点就被遍历了使得下一次不用遍历

(题目均截图来自于Acwing)

经典模板题:

1、池塘数量

 

思路:分析题意,我们只要按照前面的思路遍历一遍所有点,那么统计一下就可以了,而此处的判段条件则是为当前点是否是‘W’即代表雨水点

实现代码

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
char g[N][N];
int n,m;
bool st[N][N];//判段当前点是否走过
int dir[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};//8个方向
void dfs(int x,int y){
    if(st[x][y]) return;
    st[x][y]=true;
    for(int i=0;i<8;i++){
        int tox=x+dir[i][0];
        int toy=y+dir[i][1];
    //判段是否出界,判段下一个走的点是不是W
        if(tox>=0&&toy>=0&&tox<n&&toy<m&&g[tox][toy]=='W'){
          dfs(tox,toy);  
        }
    }
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>g[i][j];
        }
    }//输入操作
    int count=0;//统计池塘数量
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
    //判段是否被前面的dfs走过了或者直接不是W
            if(!st[i][j]&&g[i][j]=='W'){
                count++;
                dfs(i,j);
            }
        }
    }
    cout<<count;
    return 0;
}

备注:此处解释应该已经比较详细,这里用的dfs写,后面都会用y总讲的bfs做题解。另,这些图的问题通常涉及到往8个方向走和往4个方向走的差别,而这次我直接用了数组,但是其实用两层循环走更方便,就不用设数组

2、城堡问题

 思路:这道题的输入带点问题,例如输入为11,我们可以考虑将11转化成2进制为1101,按照题意,则为西北南均有墙,这道题为4个方向的问题,所以我们在遍历的时候直接将遍历的顺序设为西北东南,即左上右下,这样的话,用当前数往右移i位&1就可以得到这个数在二进制中第i位的位置,而与方向相同,例如i为2时11的第2位为0,且i为2是往右走,所以走的时候直接判断这个方向是否有门即可,将可以走的路联通在一起,即为答案,这里还要维护一下最大的房间

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
const int N=100;
int n,m;
int g[N][N];
PII q[N*N];
bool st[N][N];
int bfs(int x,int y){
    int dir[4][2]={{0,-1},{-1,0},{0,1},{1,0}};//左上右下
    int hh=0,tt=-1;
    q[++tt]={x,y};//用数组模拟队列
    int area=0;
    st[x][y]=true;
    while(hh<=tt){
        PII t=q[hh++];
        area++;
        for(int i=0;i<4;i++){
            int tox=t.x+dir[i][0];
            int toy=t.y+dir[i][1];
    //判段边界
            if(tox<0||toy<0||tox>=n||toy>=m) continue;
            if(st[tox][toy]) continue;
    //判段i方向是否有门
            if(g[t.x][t.y]>>i&1) continue;
            q[++tt]={tox,toy};
            st[tox][toy]=true;
        }
    }
    return area;
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>g[i][j];
        }
    }
    int cnt=0,area=0;//数量和面积
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(!st[i][j]){
                area=max(area,bfs(i,j));//维护最大面积
                cnt++;
            }
        }
    }
    cout<<cnt<<endl;
    cout<<area<<endl;
    return 0;
}

3、山峰和山谷

 思路:同样我们对每个点进行bfs,但是这里不是所有的联通快都要记录,所以不能直接在bfs返回条件上做判段,我们可以在传参的时候添加一个地址传递,如果这块值相同的区域,周边没有比他更高或者更矮的才计入

实现代码

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII; 
const int N =1010;
int n,g[N][N];
bool st[N][N];
PII q[N*N];
void bfs(int x,int y,bool &has_lower,bool &has_higher){
    int dir[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
    int hh=0,tt=-1;
    q[++tt]={x,y};
    st[x][y]=true;
    while(hh<=tt){
        auto t=q[hh++];
        for(int i=0;i<8;i++){
            int tox=t.x+dir[i][0];
            int toy=t.y+dir[i][1];
    //判段边界情况
            if(tox<0||toy<0||tox>=n||toy>=n) continue;
    //如果不相等就更新更高和更矮的情况
            if(g[tox][toy]!=g[x][y]){
                if(g[tox][toy]>g[x][y])  has_higher=true;
                else has_lower=true;
            }else if(!st[tox][toy]){
                q[++tt]={tox,toy};
                st[tox][toy]=true;
    //更新当前点进队列
            }
        }
    }
}

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>g[i][j];
        }
    }
    int peek=0,valley=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(!st[i][j]){
    //记录周围是否有比这块区域更高或者更矮的
                bool has_lower=false,has_higher=false;
                bfs(i,j,has_lower,has_higher);
                if(!has_higher) peek++;
                if(!has_lower) valley++;
            }
        }
    }
    cout<<peek<<" "<<valley<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值