蓝桥杯全球变暖

你有一张某海域 NxNNxN 像素的照片,".“表示海洋、”#"表示陆地,如下所示:

.##…

.##…

…##.

…####.

…###.

其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:

…#…

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入描述
第一行包含一个整数 N\ (1 \leq N \leq 1000)N (1≤N≤1000)。

以下 NN 行 NN 列代表一张海域照片。

照片保证第 1 行、第 1 列、第 NN 行、第 NN 列的像素都是海洋。、

输出一个整数表示答案。


题目解释:所有旁边是海水的陆地格子都会被淹没。若一个陆地格子上下左右都没有海水,那么它不会被淹没

考点:flood fill。flood fill是用来计算连通块个数或属性的。
思路:使用flood fill可以统计出图上有多少个小岛。然后我们可以发现,一个小岛的最边上一圈的所有格子的数量如果等于整一个岛的格子,那么这个岛就会被淹没。 因此我们要用flood fill统计两个数值。一个是岛上最边上的格子有多少个,一个是整个岛有多少个格子。

划掉的格子由于它上下左右(有一个海水就要被淹没)有海水,因此要被淹没。
只有红色圈住的那个格子上下左右都不是海水,因此不会被淹没

在这里插入图片描述
flood fill代码模板:

第一步:对每一个格子进行一遍bfs,bfs了多少次代表有多少个连通块

for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)
        if(!st[i][j] && g[i][j] == '#')
        {
            bfs(i, j, bound, total);
            cnt++;
        }

第二步:bfs

void bfs(int x, int y, int& bound, int& total)
{
    int dx[4] = {0, -1, 0, 1}, dy[4] = {-1, 0, 1, 0};
    
    queue<pii> q;
    q.push({x, y});
    st[x][y] = true;
    
    while(!q.empty())
    {
        pii t = q.front();
        q.pop();
        
        循环一次代表遍历了一个像素点
        //这就是一块,对块的操作不要在循环里面写
        for(int i = 0; i < 4; i++)
        {
            int a = t.x + dx[i], b = t.y + dy[i];
            if(a < 0 || a >= n || b < 0 || b >= n) continue;
            if(st[a][b]) continue;
            
            一系列条件判断,具体问题具体分析
            q.push({a, b});
            st[a][b] = true;
            
        }
        对具体的属性操作
    }
}

ac代码:

#include <iostream>
#include <queue>

using namespace std;

#define x first
#define y second
typedef pair<int, int> pii;

using namespace std;

const int N = 1010;

bool st[N][N];
int n;
char g[N][N];

void bfs(int x, int y, int& bound, int& total)
{
    int dx[4] = {0, -1, 0, 1}, dy[4] = {-1, 0, 1, 0};
    
    queue<pii> q;
    q.push({x, y});
    st[x][y] = true;
    
    while(!q.empty())
    {
        pii t = q.front();
        q.pop();
        
        total++;
        bool is_bound = false;
        
        //这就是一块,对块的操作不要在循环里面写
        for(int i = 0; i < 4; i++)
        {
            int a = t.x + dx[i], b = t.y + dy[i];
            if(a < 0 || a >= n || b < 0 || b >= n) continue;
            if(st[a][b]) continue;
            
            if(g[a][b] == '.') is_bound = true;
            else
            {
                q.push({a, b});
                st[a][b] = true;
            }
        }
        if(is_bound == true) bound++;
    }
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++) cin >> g[i];
    
    int cnt = 0;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(!st[i][j] && g[i][j] == '#')
            {
                int bound = 0, total = 0;
                bfs(i, j, bound, total);
                st[i][j] = true;
                if(bound == total) cnt++;
            }
    cout << cnt;
}
  • 需要强调一点:对属性的操作,不要在for循环内部进行(就是那个往四个方向展开的那个循环)。
    每一次把像素点从队列里面pop出来,代表的都是连通块数量+1.如果要统计联通块数量,统计while循环了多少次即可。
  • 数边有多少个格子也很简单,只需在for循环里面看它旁边是否有水,如果有水,证明该格子是边界的一个格子,计数+1即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值