1. 程式人生 > >哈理工OJ 1525 水神(海上葬禮)(【BFS(較困難)】)

哈理工OJ 1525 水神(海上葬禮)(【BFS(較困難)】)

地址: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;
}