哈理工OJ 1525 水神(海上葬礼)(【BFS(较困难)】)

109 篇文章 0 订阅
61 篇文章 0 订阅

地址:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1525
水神
Time Limit: 1000 MS Memory Limit: 16384 K
Total Submit: 16(5 users) Total Accepted: 6(4 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
本题很难,不过或许对于你并不算难,但对于弱鸡的我还是比较难的。
下面说下思路吧,首先搜一次,把最大的水域搜出来并标记上

void bfs1(int sx,int sy)
{
    queue<node>q;
    node fr,ne;
    fr.x=sx,fr.y=sy;
    q.push(fr);
    book1[sx][sy]=1;
    while(!q.empty())
    {
        fr=q.front();
        q.pop();
        for(int i=0; i<8; i++)
        {
            ne.x=fr.x+dir[i][0];
            ne.y=fr.y+dir[i][1];
            if(a[ne.x][ne.y]=='.'&&ne.x>=0&&ne.x<n&&ne.y>=0&&ne.y<m&&book1[ne.x][ne.y]==0)
            {
                book1[ne.x][ne.y]=1;
                q.push(ne);
            }
        }
    }
}

接下来从第一行,最后一行,第一列,最后一列分别进行第二次搜索,把最大水域外的区域全部搜出来。

void bfs2(int sx,int sy)
{
    queue<node>q;
    node fr,ne;
    fr.x=sx,fr.y=sy;
    q.push(fr);
    book2[sx][sy]=1;
    while(!q.empty())
    {
        fr=q.front();
        q.pop();
        for(int i=0; i<4; i++)
        {
            ne.x=fr.x+dir2[i][0];
            ne.y=fr.y+dir2[i][1];
            if(ne.x>=0&&ne.y>=0&&ne.x<n&&ne.y<m&&book2[ne.x][ne.y]==0&&book1[ne.x][ne.y]==0)
            {
                book2[ne.x][ne.y]=1;
                q.push(ne);
            }
        }
    }
}

下面进行第三次搜索,第三次搜索搜的是在最大水域里面的连通块的个数。因为第二次搜索把不是最大水域里的都标记出来了,第三次搜索就非常简单了,下面是第三次搜索的代码:

void bfs3(int sx,int sy)
{
    queue<node>q;
    node fr,ne;
    fr.x=sx,fr.y=sy;
    q.push(fr);
    book3[sx][sy]=1;
    while(!q.empty())
    {
        fr=q.front();
        q.pop();
        for(int i=0; i<4; i++)
        {
            ne.x=fr.x+dir2[i][0];
            ne.y=fr.y+dir2[i][1];
            if(ne.x>=0&&ne.x<n&&ne.y>=0&&ne.y<m&&book3[ne.x][ne.y]==0&&a[ne.x][ne.y]=='#'&&book2[ne.x][ne.y]==0)
            {
                book3[ne.x][ne.y]=1;
                q.push(ne);
            }
        }
    }
}

下面是完整的AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

struct node
{
    int x,y;
};
int n,m,dir[8][2]= {{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
int sx,sy,book1[505][505],book2[505][505],book3[505][505],dir2[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
char a[500][500];
void bfs1(int sx,int sy)
{
    queue<node>q;
    node fr,ne;
    fr.x=sx,fr.y=sy;
    q.push(fr);
    book1[sx][sy]=1;
    while(!q.empty())
    {
        fr=q.front();
        q.pop();
        for(int i=0; i<8; i++)
        {
            ne.x=fr.x+dir[i][0];
            ne.y=fr.y+dir[i][1];
            if(a[ne.x][ne.y]=='.'&&ne.x>=0&&ne.x<n&&ne.y>=0&&ne.y<m&&book1[ne.x][ne.y]==0)
            {
                book1[ne.x][ne.y]=1;
                q.push(ne);
            }
        }
    }
}

void bfs2(int sx,int sy)
{
    queue<node>q;
    node fr,ne;
    fr.x=sx,fr.y=sy;
    q.push(fr);
    book2[sx][sy]=1;
    while(!q.empty())
    {
        fr=q.front();
        q.pop();
        for(int i=0; i<4; i++)
        {
            ne.x=fr.x+dir2[i][0];
            ne.y=fr.y+dir2[i][1];
            if(ne.x>=0&&ne.y>=0&&ne.x<n&&ne.y<m&&book2[ne.x][ne.y]==0&&book1[ne.x][ne.y]==0)
            {
                book2[ne.x][ne.y]=1;
                q.push(ne);
            }
        }
    }
}

void bfs3(int sx,int sy)
{
    queue<node>q;
    node fr,ne;
    fr.x=sx,fr.y=sy;
    q.push(fr);
    book3[sx][sy]=1;
    while(!q.empty())
    {
        fr=q.front();
        q.pop();
        for(int i=0; i<4; i++)
        {
            ne.x=fr.x+dir2[i][0];
            ne.y=fr.y+dir2[i][1];
            if(ne.x>=0&&ne.x<n&&ne.y>=0&&ne.y<m&&book3[ne.x][ne.y]==0&&a[ne.x][ne.y]=='#'&&book2[ne.x][ne.y]==0)
            {
                book3[ne.x][ne.y]=1;
                q.push(ne);
            }
        }
    }
}
int main()
{
    while(~scanf("%d%d%d%d",&n,&m,&sx,&sy))
    {
        int sum=0;
        for(int i=0; i<n; i++)
        {
            scanf("%s",&a[i]);
        }
        memset(book1,0,sizeof(book1));
        memset(book2,0,sizeof(book2));
        memset(book3,0,sizeof(book3));
        bfs1(sx,sy);
        for(int i=0; i<n; i++)
        {
            if(book1[0][i]==0)
            {
                bfs2(0,i);
            }
        }
        for(int i=0; i<n; i++)
        {
            if(book1[n-1][i]==0)
            {
                bfs2(n-1,i);
            }
        }
        for(int i=0; i<m; i++)
        {
            if(book1[i][0]==0)
            {
                bfs2(i,0);
            }
        }
        for(int i=0; i<m; i++)
        {
            if(book1[i][m-1]==0)
            {
                bfs2(i,m-1);
            }
        }
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                if(a[i][j]=='#'&&book2[i][j]==0&&book3[i][j]==0)
                {
                    sum++;
                    bfs3(i,j);
                }
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值