DFS_全球变暖_蓝桥杯2018省赛N0.9

博客围绕全球变暖后岛屿淹没问题展开,最初采用两遍dfs搜索求前后岛屿数差值。后介绍一种惊艳思路,即找出土地周围都有海水的岛屿。还指出参考代码存在问题,修改时曾因未注意边界问题致程序崩溃。
你有一张某海域NxN像素的照片,"."表示海洋、"#"表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。  
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。  

输入格式
第一行包含一个整数N。  (1 <= N <= 1000)  
以下N行N列代表一张海域照片。  
照片保证第1行、第1列、第N行、第N列的像素都是海洋。  
输出格式
一个整数表示答案
输入样例
7 ....... .##.... .##.... ....##. ..####. ...###. ....... 输出样例 1

我拿到这题肯定知道是搜索,但是题目的意思让我匪夷所思,后来慢慢才懂题目的意思。懂了之后,和大多数人的想法一样,两遍dfs搜索找遍全球变暖前后的岛屿数然后相减就是最后的答案。

有篇博主的答案给的代码让我觉得他的想法挺惊艳的,既然求照片中有多少岛屿会被完全淹没,那么只需要找出那些在搜索过程中岛屿上的土地周围都存在海水的岛屿就好了,至于其他有那种四周都有土地的岛屿,它最后只剩一块土地也好,它分成2,3个岛屿也罢,我都不需要去管

另外,那个源代码有挺多问题的,我改了一下,开始没注意到边界问题,程序直接崩了

#include<iostream>
#include<cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n;
char map[110][110];
int ans[11000];
int vis[110][110];

void dfs(int x, int y, int k)
{
    if(map[x][y]=='.'||vis[x][y]||x<0||y<0||x>=n||y>=n)
        return;
    vis[x][y]=1;
    if(map[x-1][y]=='#'&&map[x+1][y]=='#'&&map[x][y-1]=='#'&&map[x][y+1]=='#')
        ans[k]++;
    dfs(x+1, y, k);
    dfs(x-1, y, k);
    dfs(x, y-1, k);
    dfs(x, y+1, k);
}
int main()
{
    memset(vis, 0, sizeof(vis));
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%s", &map[i]);

    int cnt=0;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            if(map[i][j]=='#'&&!vis[i][j]) {
                dfs(i, j, cnt);
                cnt++;
            }
        }
    }
    
    int sum=0;
    for(int i = 0; i < cnt; i++)
        if(ans[i]==0)
            sum++;
    printf("%d\n",sum);
    
    return 0;
}

参考自:https://www.cnblogs.com/flightless/p/8718443.html

转载于:https://www.cnblogs.com/wizarderror/p/10547871.html

<think>嗯,用户需要2018蓝桥杯C++试题中关于全球变暖的题解。首先,我得回忆一下这个题目的具体内容。题目应该是在一个N×N的网格中,每个格子代表一块陆地或海洋。题目要求确定有多少岛屿会被完全淹没,也就是原本的岛屿中,有多少岛屿的所有陆地格子都与海洋相邻,导致全球变暖后这些陆地全部变成海洋。 接下来,我需要考虑如何解决这个问题。首先,要理解岛屿的定义。岛屿是由相邻的陆地组成的,上下左右四个方向相邻的陆地属于同一个岛屿。然后,全球变暖导致所有临海的陆地(即上下左右有至少一个海洋的陆地)都会被淹没。因此,如果一个岛屿中的所有陆地格子都至少有一个相邻的海洋,那么这个岛屿会被完全淹没;反之,如果有至少一个陆地格子周围没有海洋,那么这个岛屿就不会被完全淹没,因为那个陆地不会被淹没,岛屿仍有残留。 那解决步骤应该是这样的:首先遍历整个网格,找到所有岛屿,然后对每个岛屿检查是否所有陆地格子都是临海的。如果是,则统计到结果中。否则不统计。 具体实现的话,可以用深度优先搜索(DFS)或广度优先搜索(BFS)来标记和遍历每个岛屿。对于每个岛屿中的每个陆地格子,检查其四周是否有海洋。如果存在至少一个陆地格子四周都没有海洋,则整个岛屿不会被完全淹没;否则,该岛屿会被统计。 需要注意的问题包括网格的边界处理,确保数组不越界。此外,如何高效地遍历每个岛屿,并标记已访问的格子,避免重复计算。 然后,我需要参考用户提供的引用链接中的代码。根据用户提供的引用链接,可能这两个博客中有相关的题解。但用户现在无法直接访问这些链接,所以我需要根据常见的解法来构建答案。例如,使用BFS遍历每个岛屿,并为每个岛屿记录是否存在不会被淹没的陆地。 可能的代码结构是:读取输入,遍历每个格子,如果是未访问的陆地,则进行BFS,同时检查该岛屿中是否存在至少一个陆地格子四周没有海洋。如果不存在这样的格子,说明整个岛屿会被淹没,计数器加一。 然后,生成相关问题,可能涉及算法优化、不同解法比较、题目变种等。 现在,把这些思路整理成结构化的答案,确保符合用户要求的格式,比如使用中文,行内数学表达式用$...$,独立公式用$$...$$,正确使用LaTeX语法,并生成相关问题。</think>### 蓝桥杯2018 C++ 全球变暖题解 #### 问题描述 给定$N×N$的网格地图,每个单元格包含`#`(陆地)或`.`(海洋)。全球变暖导致**四周存在海洋的陆地**被淹没。要求计算有多少岛屿会完全消失(即原岛屿中所有陆地均被淹没)[^1]。 #### 解题思路 1. **岛屿识别**:使用BFS/DFS遍历连通陆地,标记已访问区域 2. **淹没判断**:对每个岛屿检查是否存在至少一个陆地单元格满足: $$ \forall \text{相邻方向} \ (dx,dy),\ grid[x+dx][y+dy] ≠ "." $$ 即该陆地四周无海洋,属于不会被淹没的"安全点" #### 代码实现 ```cpp #include <iostream> #include <queue> using namespace std; const int N = 1005; char grid[N][N]; bool vis[N][N]; int dir[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}}; bool hasSafePoint(int x, int y, int n) { for(int i=0; i<4; i++){ int nx = x + dir[i][0]; int ny = y + dir[i][1]; if(nx<0 || nx>=n || ny<0 || ny>=n) continue; if(grid[nx][ny] == &#39;.&#39;) return false; } return true; } int main() { int n, res = 0; cin >> n; for(int i=0; i<n; i++) cin >> grid[i]; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(grid[i][j]==&#39;#&#39; && !vis[i][j]) { queue<pair<int,int>> q; q.push({i,j}); vis[i][j] = true; bool hasSafe = false; while(!q.empty()) { auto [x,y] = q.front(); q.pop(); if(hasSafePoint(x,y,n)) hasSafe = true; for(int d=0; d<4; d++) { int nx = x + dir[d][0]; int ny = y + dir[d][1]; if(nx>=0 && nx<n && ny>=0 && ny<n && grid[nx][ny]==&#39;#&#39; && !vis[nx][ny]) { vis[nx][ny] = true; q.push({nx,ny}); } } } if(!hasSafe) res++; } } } cout << res << endl; return 0; } ``` #### 算法分析 - 时间复杂度:$O(N^2)$,每个单元格最多访问一次 - 空间复杂度:$O(N^2)$,存储访问标记和队列空间 - 核心技巧:在BFS过程中同时进行安全点检测,避免二次遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值