Flood Fill模型

这个模型主要用来求连通块的数量,在求连通块时有“8连通”和“4连通”之分。

看上面的图形,如果是4连通那么红色和绿色就不连通(只有一个格子的“上下左右”相连才叫连通)。如果是8连通那就联通(不仅仅包含边相连,共顶点也叫连通)。

1097. 池塘计数 - AcWing题库

#include<iostream>
#include<utility>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
queue<PII> q;
const int N = 1010;
char g[N][N];
bool st[N][N];
int dx[8] = {-1,-1,0,1,1,1,0,-1};
int dy[8] = {0,1,1,1,0,-1,-1,-1};
int n,m,tmp=0;
void bfs(int sx,int sy){                               //BFS模板
    PII p = make_pair(sx,sy);
    q.push(p);
    st[sx][sy] = true;                                //首先,起点入队
    while(!q.empty()){                                //只要队列不空
        PII v = q.front();
        q.pop();
        int ax = v.first;
        int ay = v.second;
        for(int i=0;i<8;i++){                         //遍历与此时这个点相邻的点
            int nx = ax+dx[i];
            int ny = ay+dy[i];
            if(st[nx][ny]) continue;
            if(nx <1 || nx >n || ny <1 || ny >m) continue;
            if(g[nx][ny]=='.') continue;
            q.push(make_pair(nx,ny));                 //入队
            st[nx][ny] = true;                        //改变状态
        }
        
    }
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
        }
    }
    

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(g[i][j]=='W' && !st[i][j]){
                bfs(i,j);
                tmp++;
            }
        }
    }
    
    cout<<tmp;
}

接下来讲一下一个比较难的题目(难在图的表示):
 

  1   2   3   4   5   6   7  
   #############################
 1 #   |   #   |   #   |   |   #
   #####---#####---#---#####---#
 2 #   #   |   #   #   #   #   #
   #---#####---#####---#####---#
 3 #   |   |   #   #   #   #   #
   #---#########---#####---#---#
 4 #   #   |   |   |   |   #   #
   #############################
           (图 1)

   #  = Wall   
   |  = No wall
   -  = No wall

   方向:上北下南左西右东。

图1是一个城堡的地形图。

请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。

城堡被分割成 nm个方格区域,每个方格区域可以有0~4面墙。

注意:墙体厚度忽略不计。

第一行包含两个整数 m 和 n,分别表示城堡南北方向的长度和东西方向的长度。

接下来 m 行,每行包含 n 个整数,每个整数都表示平面图对应位置的方块的墙的特征。

每个方块中墙的特征由数字 P 来描述,我们用1表示西墙,2表示北墙,4表示东墙,8表示南墙,PP 为该方块包含墙的数字之和。

例如,如果一个方块的 P 为3,则 3 = 1 + 2,该方块包含西墙和北墙。

城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。

输入的数据保证城堡至少有两个房间。

注意,这里面(1表示西墙,2表示北墙,4表示东墙,8表示南墙

注意:我们得到的P是这些数字加起来的,因此,我们如果想看下一个位置通不通,只需要取相应位置的二进制数就可以了。比如:

现在一个方格的P是3(既1+2)我想看他的北面有没有墙。我们首先给这四个方向编一个号(西:0,北:1,东:2,南:3。这里可以用循环遍历四个方向!!)我们用P>>1,这是将P右移1位,这样原来的(3既0011)就变成001了然后我们再&1这样就可以得到最低位是0还是1了。

#include<iostream>
#include<queue>
#include<algorithm>
#include<utility>
using namespace std;
typedef pair<int,int> PII;
const int N = 55;
queue<PII> q;
int n,m,cnt,mara;
int g[N][N];
bool st[N][N];

int dx[] = {0,-1,0,1};
int dy[] = {-1,0,1,0};

int bfs(int sx,int sy){
    q.push(make_pair(sx,sy));
    st[sx][sy] = true;
    int tem=1;//起点也算一个房间
    while(!q.empty()){
        PII p = q.front();
        q.pop();
        for(int i = 0; i<4 ;i++){
            int nx = p.first + dx[i];
            int ny = p.second + dy[i];
            if(!st[nx][ny] && nx>=1 && nx<=n && ny>=1 && ny<=m && !(g[p.first][p.second]>>i&1)){//注意这里g[][]测试的是基点,而不是要遍历的点
                q.push(make_pair(nx,ny));
                st[nx][ny] = true;
                tem++;
            }
        }

    }
    return tem;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>g[i][j];
        }
    }


    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!st[i][j]){
                mara = max(bfs(i,j),mara);
                cnt++;
            }
        }
    }

    cout<<cnt<<endl<<mara;


    return 0;
}

1106. 山峰和山谷 - AcWing题库

#include<iostream>
#include<utility>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1010;
typedef pair<int,int> PII;
int g[N][N];
bool st[N][N];
int n,ah,al;
int dx[] = {-1,-1,0,1,1,1,0,-1};
int dy[] = {0,1,1,1,0,-1,-1,-1};


void bfs(int sx,int sy,bool &hashigher,bool &haslower){
    queue<PII> q;
    q.push(make_pair(sx,sy));
    st[sx][sy] = true;
    while(!q.empty()){
        PII p = q.front();
        q.pop();
        for(int i=0;i<8;i++){
            int nx = p.first + dx[i];
            int ny = p.second + dy[i];
            if(nx <1 || nx >n || ny <1 ||ny >n) continue;//超过界限的忽略
            if(g[p.first][p.second]==g[nx][ny]){         //其周围的格子值,要么相等,要么不相等
                if(!st[nx][ny]){                         //没有被访问过,才能进行入队
                    q.push(make_pair(nx,ny));
                    st[nx][ny] = true;
                }else continue;
            }
            else{                                        //格子值不相等
                if(g[p.first][p.second] < g[nx][ny]) hashigher=true;  //至少存在一个比这个高的。
                else haslower=true;     //至少存在一个比这个小的。
            }
        }
    }
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>g[i][j];
        }
    }
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(!st[i][j]){
                bool hashigher=false,haslower=false;
                bfs(i,j,hashigher,haslower);
                if(hashigher && haslower)  continue;//既有比它高的也有比它小的。
                if(!hashigher) ah++;    //如果没有比这个高的。那么这个最高。
                if(!haslower)  al++;    //如果没有比这个小的,那么这个最小。
                
            }
        }
    }
    
    cout<<ah<<" "<<al<<endl;
    
    
    
    return 0;
}

这个BFS设计的很灵活,从中可以理解到:如何进行BFS?关键步骤就是哪些入队列,哪些不入队列。这个题很巧妙,只有相等的才入队列,并将其状态设置位true。其他的不入队列,因此没有必要设置为true(如果设置了,反而会发生错误,导致后面遍历地图时自动略过这个点)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

背水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值