lightoj 1150 - Ghosts! 【BFS + 二分查找 + 判二分图完美匹配】

1150 - Ghosts!
Time Limit: 2 second(s)Memory Limit: 32 MB

It's a dark, cloudy and spooky night. The ghosts of 'VutPara' graveyard have awakened. They are planning to take revenge against humans. They are dead but the humans are alive that's their main headache. So, they want to frighten all the people nearby.

'Vutpara' can be described as an n x n grid. Each cell can be one of the following types:

'.' - The cell is empty

'G' - The cell contains a ghost

'H' - The cell contains a human

'#' - The cell contains over-polluted air, the ghosts can't fly over this cell

The ghosts can move vertically or horizontally but not diagonally. And they can fly to any cell if the air is not over-polluted. It takes one minute to move to an adjacent cell. And it takes two minutes to frighten a human if the ghost is flying over the human (means that the position of the ghost and the human is same). But the ghosts are quite lazy, so any ghost can frighten at most one human. And after their work is done they want to go back to their grave (Initial position).

The night is getting over and they have a little time left. As they are smart enough they know all the human positions and the map. Now they want to frighten all the humans in the map using minimum time.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a blank line and an integer n (5 ≤ n ≤ 25). Then n lines follow. Each of the line contains n characters each describing 'Vutpara'. You can assume that number of ghosts is always greater than or equal to the number of humans and the number of ghosts is no more than 50. And there is at least one human in the map.

Output

For each case of input, print the case number and the minimum time needed to frighten all the people or 'Vuter Dol Kupokat' if it's not possible to frighten all the people.

Sample Input

Output for Sample Input

4

 

8

....##..

.....#..

..#...G.

G...####

H#..HG.G

#....#.#

H.#G..H.

..##...#

 

6

......

G.....

......

......

......

.....H

 

6

.....G

.H....

......

......

....H.

G.....

 

6

#.#G#.

G....#

G..##.

H###.#

...#H#

..#GHH

Case 1: 12

Case 2: 20

Case 3: 12

Case 4: Vuter Dol Kupokat

 


PROBLEM SETTER: JANE ALAM JAN


题意:有一个n*n的地图,图中有4种字符。'#'表示此处不能过,'G'表示一个幽灵,'H'表示一个人,'.'表示此处可以过,幽灵每走一步需要1单位时间。已知每个幽灵最多针对一个人且需要花费2个单位时间,幽灵是十分聪明的。现在问你所有人会不会全部被针对,若会输出幽灵完成这一切所需的最少时间(加上幽灵回到初始位置的时间),否则输出Vuter Dol Kupokat。


思路:BFS预处理图的最短路,然后枚举时间值mid,根据mid值建二分图,判能否完美匹配。



AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define MAXN 60
#define INF 0x3f3f3f3f
using namespace std;
int dist[MAXN][MAXN][MAXN];
int N, M;//幽灵数 人数
struct perfectmatch
{
    int Map[MAXN][MAXN];
    bool used[MAXN];
    int match[MAXN];
    int DFS(int x)
    {
        for(int i = 1; i <= N; i++)
        {
            if(Map[x][i] && !used[i])
            {
                used[i] = true;
                if(match[i] == -1 || DFS(match[i]))
                {
                    match[i] = x;
                    return 1;
                }
            }
        }
        return 0;
    }
    bool judge()
    {
        int ans = 0;
        memset(match, -1, sizeof(match));
        for(int i = 1; i <= M; i++)
        {
            memset(used, false, sizeof(used));
            ans += DFS(i);
        }
        return ans == M;
    }
}PM;
int n; char str[MAXN][MAXN];
struct rec{
    int x, y;
    int step;
};
rec g[MAXN], h[MAXN];
void getMap()
{
    scanf("%d", &n);
    N = M = 0;
    for(int i = 0; i < n; i++)
    {
        scanf("%s", str[i]);
        for(int j = 0; j < n; j++)
        {
            if(str[i][j] == 'G')
                g[++N].x = i, g[N].y = j;
            if(str[i][j] == 'H')
                h[++M].x = i, h[M].y = j;
        }
    }
}
void new_map(int mid)
{
    memset(PM.Map, 0, sizeof(PM.Map));
    for(int i = 1; i <= M; i++)
        for(int j = 1; j <= N; j++)
            if(dist[i][g[j].x][g[j].y] <= mid)
                PM.Map[i][j] = 1;
}
bool vis[MAXN][MAXN];
bool Can(rec a){
    return a.x >= 0 && a.x < n && a.y >= 0 && a.y < n && str[a.x][a.y] != '#' && !vis[a.x][a.y];
}
void BFS(int id, int sx, int sy)
{
    memset(vis, false, sizeof(vis));
    int Move[4][2] = {0,1, 0,-1, 1,0, -1,0};
    queue<rec> Q;
    rec now, next;
    now.x = sx, now.y = sy, now.step = 0;
    Q.push(now);
    while(!Q.empty())
    {
        now = Q.front();
        Q.pop();
        dist[id][now.x][now.y] = now.step;
        for(int k = 0; k < 4; k++)
        {
            next.x = now.x + Move[k][0];
            next.y = now.y + Move[k][1];
            if(Can(next))
            {
                next.step = now.step + 1;
                vis[next.x][next.y] = true;
                Q.push(next);
            }
        }
    }
}
int k = 1;
void solve()
{
    memset(dist, INF, sizeof(dist));
    for(int i = 1; i <= M; i++)
        BFS(i, h[i].x, h[i].y);
    int l = 0, r = 1200, mid;
    int ans = INF;
    while(r >= l)//二分
    {
        mid = (l + r) >> 1;
        new_map(mid);
        if(PM.judge())//完美匹配
            ans = mid, r = mid - 1;
        else
            l = mid + 1;
    }
    printf("Case %d: ", k++);
    if(ans == INF)
        printf("Vuter Dol Kupokat\n");
    else
        printf("%d\n", ans * 2 + 2);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        getMap();
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值