全球变暖(dfs和bfs)

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

.......
.##....
.##....
....##.
..####.
...###.
.......

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

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。

具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

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

.......
.......
.......
.......
....#..
.......
.......

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

输入

第一行包含一个整数N。

以下 N行 N列,包含一个由字符”#”和”.”构成的 N×N字符矩阵,代表一张海域照片,”#”表示陆地,”.”表示海洋。

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

输出

一个整数表示答案。

DFS

难点在于如何来判断哪些会被一次性沉没,题目说只要有一边是靠近海洋的就会在下一次被淹没,那么换句话说就是被全部土地包围的那个地方就不会被淹没,那么问题就等于如果我一个岛屿全是临海的就会消失,岛屿的边缘的土地就是全部土地。

那么dfs代码就好写多了,一个total变量存储这个岛屿所有土地个数,一个brink变量存储所有靠海土地的个数,如果两个相等就说明这个岛屿会消失

#include<bits/stdc++.h>
using namespace std;
const int N=10010; 
bool st[N][N];//保存拜访过的点
int n;
char g[N][N];
int total,brink;//total表示岛屿#的个数,brink表示与海接触的#的个数,如果两者相等就说明这个岛屿四面临海会被淹没
const int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};//矢量数组
void dfs(int x,int y){
    st[x][y]=true;
    total++;
    
    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if(tx>=0&&tx<n&&ty>=0&&ty<n&&g[tx][ty]=='.'){
            brink++;
            break;//注意这里一定要及时退出不然会重复计算土地个数
        }
    }
    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if(tx>=0&&tx<n&&ty>=0&&ty<n&&g[tx][ty]=='#'&&!st[tx][ty]){
            dfs(tx,ty);
        }
    }
}
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(g[i][j]=='#'&&!st[i][j]){
                total = brink=0;
                dfs(i,j);
                //cout<<total<<" "<<brink<<endl;
                if(total==brink)
                cnt++;
            }
        }
    }
    cout<<cnt;
    return 0;
}

BFS

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
char g[N][N];
int n;
bool st[N][N];
int total,brink;
const int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
typedef pair<int,int> PII;
void bfs(int x,int y){
    queue<PII> q;//队列
    st[x][y] = true;
    q.push({x,y});
    while(q.size()){
        PII temp = q.front();
        q.pop();
        total++;
        for(int i=0;i<4;i++){
        int tx=temp.first+dx[i],ty=temp.second+dy[i];
        if(tx<0&&tx>=n&&ty<0&&ty>=n)
            continue;
        if(g[tx][ty]=='.')
        {
            brink++;
            break;
        }
        }
        
        for(int i=0;i<4;i++){
            int tx=temp.first+dx[i],ty=temp.second+dy[i];
            if(tx<0&&tx>=n&&ty<0&&ty>=n)
            continue;
            if(g[tx][ty]=='#'&&!st[tx][ty]){
                q.push({tx,ty});
                st[tx][ty]=true;
            }
        }
    }
    
}

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(g[i][j]=='#'&&!st[i][j]){
                total = brink =0;
                bfs(i,j);
                //cout<<total<<" "<<brink<<endl;
                if(total==brink)
                cnt++;
            }
        }
    }
    cout<<cnt;
    return 0;
}

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值