Flood Fill 算法

Flood Fill 算法主要用于查找连通块,用bfs来进行搜索

板子题:池塘计数

思路:遍历一遍,用bfs,记得判重。

#include <iostream>
#include <queue>
using namespace std;
const int N = 1021;
char ph[N][N];int n,m; bool st[N][N];
#define x first 
#define y second 
typedef pair<int,int> PII;
void bfs(int sx, int sy) {
    queue<PII> q; q.push({sx,sy}); st[sx][sy] = true; // status数组判重
    while(q.size()) { // 开始进行bfs
        auto t = q.front(); q.pop();  // 出队
        // 这里采用的是九宫格型,也可以用PII表示八个方向
        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 || st[i][j]) continue; // 越界
                if(i == t.x && j = t.y) continue; // 等于中间值
                if(ph[i][j] == '.') continue; // 不是'W'
                q.push({i,j}); // 入队
                st[i][j] = true;
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i = 0; i < n; ++i) {cin>>ph[i];} // input
    int ans = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            if(!st[i][j]) {
                ans++; // 每当有一个有'W'时,就表明会有一个连通块的,即答案加一
                bfs(i,j); // bfs
            }
        }
    }
    cout<<ans;
}

城堡问题

求最大连通块和连通块个数
思路:连通块个数与上一题类似,最大连通块 采用bfs时进行计数,找连通块的大小。
关于方向,用到位运算的相关知识。

#include <iostream>
#include <queue>
using namespace std;
#define x first 
#define y second 
typedef pair<int,int> PII;
// 方向不能乱,与要求数字表示的方向有关
PII pt[4] = {
    {0,-1}, {-1,0}, {0,1}, {1,0}
};
const int N = 54;
int ph[N][N];
bool st[N][N];
int n,m,cnt,ret,temp;
// 返回值为连通块大小
int bfs(int sx, int sy) {
    queue<PII> q; q.push({sx,sy});
    st[sx][sy] = true;
    int ans = 0;
    while(q.size()) {
        auto t = q.front(); q.pop();
        ans++;
        for(int i = 0; i < 4; ++i) {
            int xx = t.x + pt[i].first, yy = t.y + pt[i].second;
            if(xx < 0 || xx >= n || yy < 0 || yy >= m || st[xx][yy]) continue; // 越界 或者已经访问过
            if(ph[t.x][t.y] >> i & 1) continue; // 是否有墙,有墙continue
            q.push({xx,yy}); st[xx][yy] = true; 
        }
    }
    return ans;
}
int main()
{
    cin>>n>>m;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) cin>>ph[i][j];
    }
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            if(!st[i][j]) {
                cnt++; // 连通块个数
                ret = max(ret, bfs(i,j));
            }
        }
    }
    cout<<cnt<<"\n"<<ret;
}

山峰和山谷

思路:在一个九宫格内,它是最大的w,就表明,它一定是山峰,山谷亦然。在一个有更大的有更小的内,一定是山脉。

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1021;
#define x first 
#define y second
typedef pair<int,int> PII;
int n, ph[N][N]; bool st[N][N];
// 引用传递,因为要知道一个一个块内的多个值(thanhi,thanlo)
void bfs(int sx, int sy, bool &hi, bool &lo) {
    queue<PII> q; q.push({sx,sy});st[sx][sy] = true;
    while(q.size()) {
        auto 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 >= n) continue; // 越界
                // 与中间值不相同,表明存在大小关系比

                if(ph[i][j] != ph[t.x][t.y]) { 
                    // 比中间值大
                    if(ph[i][j] > ph[t.x][t.y]) hi = true;
                    // 比中间值小
                    else lo = true;
                } else if(!st[i][j]) { // 相同,记得判重,因为可能再入队一个中间值,导致死循环。
                    q.push({i,j}); st[i][j] = true;
                }
            }
        }
    }
}
int main()
{
    cin>>n;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) cin>>ph[i][j];
    }
    int peak = 0, valley = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            if(!st[i][j]) {
                bool thanhi = false, thanlo = false; // thanhi 是否有比ph[i][j] 大的值, thanlo 是否有比ph[i][j] 小的值
                bfs(i,j,thanhi, thanlo);
                if(!thanhi) peak++; // 没有 就是山峰
                if(!thanlo) valley++; // 有就是山谷
            }
        }
    }
    cout<<peak<<" "<<valley;
}

今日算法学习总结:更系统的学了搜索,对递归有了更深的认识。关于递归,不要沉迷它的循环过程,这会让解题更加迷茫。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

golemon.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值