Lightoj 1150 Ghosts!(bfs+二分+二分图)

1150 - Ghosts!

   PDF (English)StatisticsForum
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

 


题目大意:给一个地图,有一些怪兽和人,每个怪兽都要去吓一个人,怪兽只能走上下左右四个方向,一个怪兽只会吓一个人,吓一个人要两分钟,走一个格子要1分钟,问最后吓完所有人要多久

首先对怪兽进行广搜,找出他们离每一个人的距离,然后存起来,考虑到怪兽吓人是同时进行的,在某一个时间一定是所有怪物都把人吓完了并回去了,所以我们就二分这个时间,在这个时间内如果可以完成这个任务,就连一条边,建起一个图,跑一遍匈牙利即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=710;
const int maxm=200010;
const int inf=0x3f3f3f3f;
typedef pair<int,int> P;
struct LDJ
{
    int x;
    int y;
    int step;
};
struct Node
{
    int to;
    int next;
}edge[maxm];
int n;
int cnt;
int head[maxn];
char map[30][30];
int num[30][30];
int dis[30][30];
bool vis[30][30];
int odd,even;
int dirx[]={0,1,0,-1};
int diry[]={1,0,-1,0};
int match[710];
bool match_vis[710];
vector<P> G[710];
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    return;
}
void add(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    return;
}
void bfs(int x,int y)
{
    queue<LDJ> que;
    LDJ start;
    start.x=x;
    start.y=y;
    start.step=0;
    que.push(start);
    //memset(dis,inf,sizeof(dis));
    memset(vis,false,sizeof(vis));
    //dis[x][y]=0;
    vis[x][y]=true;
    while(!que.empty())
    {
        LDJ now=que.front();
        que.pop();
        int nowx=now.x;
        int nowy=now.y;
        for(int k=0;k<4;k++)
        {
            int nx=nowx+dirx[k];
            int ny=nowy+diry[k];
            if(nx>=1&&ny>=1&&nx<=n&&ny<=n&&!vis[nx][ny]&&map[nx][ny]!='#')
            {
                
                //dis[nx][ny]=dis[nowx][nowy]+1;
                vis[nx][ny]=true;
                LDJ tmp;
				tmp.x=nx;
				tmp.y=ny;
                tmp.step=now.step+1;
				que.push(tmp);
                if(map[nx][ny]=='H')
                {
                    G[num[x][y]].push_back(make_pair(num[nx][ny],tmp.step*2+2));
                }
            }
        }
    }
    return;
}
bool dfs(int node)
{
    for(int i=head[node];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!match_vis[v])
        {
            match_vis[v]=true;
            if(match[v]==-1||dfs(match[v]))
            {
                match[v]=node;
                return true;
            }
        }
    }
    return false;
}
int hungry()
{
    int ans=0;
    memset(match,-1,sizeof(match));
    for(int i=1;i<=odd;i++)
    {
        memset(match_vis,false,sizeof(match_vis));
        if(dfs(i))
        {
            ans++;
        }
    }
    return ans;
}
void build(int limit)
{
    for(int i=1;i<=odd;i++)
    {
        int len=G[i].size();
        for(int j=0;j<len;j++)
        {
            P tmp=G[i][j];
            if(tmp.second<=limit)
            {
                add(i,tmp.first);
            }
        }
    }
    return;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int test;
    scanf("%d",&test);
    for(int cas=1;cas<=test;cas++)
    {
        odd=0;
        even=0;
        memset(num,0,sizeof(num));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",map[i]+1);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(map[i][j]=='G')
                {
                    num[i][j]=++odd;
                }
                if(map[i][j]=='H')
                {
                    num[i][j]=++even;
                }
            }
        }
        for(int i=0;i<=odd;i++)
        {
            G[i].clear();
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(map[i][j]=='G')
                {
                    bfs(i,j);
                }
            }
        }
        int left=0;
        int right=100000;
        int ans=-1;
        while(left<=right)
        {
            int mid=(left+right)>>1;
            init();
            build(mid);
            if(hungry()>=even)
            {
                ans=mid;
                right=mid-1;
            }
            else
            {
                left=mid+1;
            }
        }
        if(ans==-1)
		{
			printf("Case %d: Vuter Dol Kupokat\n",cas);
		}
		else
		{
			printf("Case %d: %d\n",cas,ans);
		}
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值