hrbust 1525 水神【纪念搜索题解100篇】【Bfs】

本文介绍了一道算法题,任务是确定一张地图上由海洋环绕的岛屿数量,以决定可作为古老部族巫师墓地的最大数目。通过两次广度优先搜索(BFS),分别计算所有岛屿总数和特定海域外的岛屿数,进而得出指定海域内的最大埋葬数量。

水神

Time Limit: 1000 MS

Memory Limit: 16384 K

 

Total Submit: 19(5 users)

Total Accepted: 7(5 users)

Rating: 

Special Judge: No

 

Description

有一片被大海包围的群岛,岛上居住着一个古老的部族。很多年前部落里有一位巫师接受了水神的召唤跳入海中,从此,那一片海域就被打上了水神的烙印,被这片海域所包围的陆地也被赋予了神圣的意义(包围关系满足传递性,即海域A包围了岛B,岛B包围了海域C,而海域C中包含了岛D,则我们说海域A也包含了岛D)。

 

从那以后,部落里的巫师死后都必须葬在这片神圣海域所包围的岛上,而且每一个岛都只能埋葬一位巫师(否则就会被视为对水神的不敬,从而给部族带来灾难)。现在给你群岛的地图和最初那位巫师跳海的地方,请你计算一下最多可以埋葬多少巫师。 

 

地图是一个n*m的字符矩阵,’#’代表陆地,’.’代表海洋。连通的一片陆地为一个岛,连通的一片海洋为一个海域。其中,陆地从上、下、左、右4个方向连通,海洋从上、下、左、右、左上、左下、右上、右下8个方向连通。

如下图。

 图中有4个岛,2片海域。如果在A处落水,则落水的海域包围了除右上、左下两个顶角外的3个岛屿;如果在B处落水,则只包含了中间的2个岛。

 

 

Input

有多组测试数据,不超过10组。

对于每组测试数据,输入的第一行为n, m, x, y, n和m表示地图的大小(1<=n,m<=500),x和y(0 <= x < n, 0 <= y < m)是巫师跳海的地方,数据保证巫师跳海的地方是一个水域。

接下来为一个n*m的字符矩阵,共n行,每行m个字符。

Output

对于每组测试数据,输出一行,包含一个整数,为最多可以埋葬的巫师数量。

Sample Input

7 9 0 0

........#

.#######.

.#.....#.

.#.#.#.#.

.#.....#.

.#######.

#........

7 9 2 6

........#

.#######.

.#.....#.

.#.#.#.#.

.#.....#.

.#######.

#........

Sample Output

3

2

Author

黄李龙@HRBUST


这里纠正一个题目中说明不对的地方,那是5个,不是4个岛。


思路:

1、首先我们统计一下一共有多少岛屿,这里暴力求就可以。


2、根据巫师跳海的地方,我们再Bfs一下,求一下这个围成的海域所组成的界限,对于海域能够扩散所围的地方,我们在vis【】【】中标记为1,如果不能扩散到的地方,标记为0.


3、因为直接求海域内部的岛屿数比较费劲一些,所以我们求海域外的岛屿数,然后用总岛屿数减去海域外岛屿数,即为所求,这里我们找到一个海域外的岛我们就将这个岛变成“.”,以防止多次计算岛屿,或者是计算少岛屿的情况。


AC代码:

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct zuobiao
{
    int x,y;
}now,nex;
int n,m,sx,sy,output;
char a[505][505];
int vis[505][505];
int vis2[505][505];
int vis3[505][505];
int fx[8]={0,0,1,-1,1,-1,1,-1};
int fy[8]={1,-1,0,0,1,-1,-1,1};
void Bfs0(int x,int y)//统计一共有多少岛屿
{
    queue<zuobiao >s;
    now.x=x;
    now.y=y;
    vis[now.x][now.y]=1;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=m&&vis[nex.x][nex.y]==0&&a[nex.x][nex.y]=='#')
            {
                vis[nex.x][nex.y]=1;
                s.push(nex);
            }
        }
    }
}
void Bfs(int x,int y)//Bfs能扩散的海域
{
    memset(vis,0,sizeof(vis));
    queue<zuobiao >s;
    now.x=x;
    now.y=y;
    vis[x][y]=1;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<8;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=m&&vis[nex.x][nex.y]==0&&a[nex.x][nex.y]=='.')
            {
                vis[nex.x][nex.y]=1;
                s.push(nex);
            }
        }
    }
}
void Bfs3(int x,int y)//将海域外的岛屿整个移除
{
    memset(vis3,0,sizeof(vis3));
    queue<zuobiao >s;
    now.x=x;
    now.y=y;
    vis3[now.x][now.y]=1;
    s.push(now);
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=1&&nex.x<=n&&nex.y>=1&&nex.y<=m&&vis3[nex.x][nex.y]==0&&a[nex.x][nex.y]=='#')
            {
                vis3[nex.x][nex.y]=1;
                s.push(nex);
                a[nex.x][nex.y]='.';
            }
        }
    }
}
void Bfs2(int x,int y)//找海域外的岛屿
{
    memset(vis2,0,sizeof(vis2));
    now.x=x;
    now.y=y;
    queue<zuobiao >s;
    s.push(now);
    vis2[x][y]=1;
    while(!s.empty())
    {
        now=s.front();
        s.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+fx[i];
            nex.y=now.y+fy[i];
            if(nex.x>=0&&nex.x<=n+1&&nex.y>=0&&nex.y<=m+1&&vis2[nex.x][nex.y]==0&&vis[nex.x][nex.y]==0)
            {
                vis2[nex.x][nex.y]=1;
                if(a[nex.x][nex.y]=='#')
                {
                    output++;//每一次在海域外找到一个岛屿,都计数一次。
                    Bfs3(nex.x,nex.y);
                }
                else
                {
                    s.push(nex);
                }
            }
        }
    }
}
int main()
{
    while(~scanf("%d%d%d%d",&n,&m,&sx,&sy))
    {
        memset(a,'.',sizeof(a));
        memset(vis2,0,sizeof(vis2));
        memset(vis3,0,sizeof(vis3));
        memset(vis,0,sizeof(vis));
        output=0;
        sx++;sy++;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",a[i]+1);
        }
        memset(vis,0,sizeof(vis));
        int cont=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(vis[i][j]==0&&a[i][j]=='#')
                {
                    cont++;
                    Bfs0(i,j);
                }
            }
        }
        Bfs(sx,sy);
        Bfs2(0,0);
        printf("%d\n",cont-output);
    }
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值