Rain on your Parade HDU - 2389(二分图匹配 HK算法)

You’re giving a party in the garden of your villa by the sea. The party is a huge success, and everyone is here. It’s a warm, sunny evening, and a soothing wind sends fresh, salty air from the sea. The evening is progressing just as you had imagined. It could be the perfect end of a beautiful day. 
But nothing ever is perfect. One of your guests works in weather forecasting. He suddenly yells, “I know that breeze! It means its going to rain heavily in just a few minutes!” Your guests all wear their best dresses and really would not like to get wet, hence they stand terrified when hearing the bad news. 
You have prepared a few umbrellas which can protect a few of your guests. The umbrellas are small, and since your guests are all slightly snobbish, no guest will share an umbrella with other guests. The umbrellas are spread across your (gigantic) garden, just like your guests. To complicate matters even more, some of your guests can’t run as fast as the others. 
Can you help your guests so that as many as possible find an umbrella before it starts to pour? 

Given the positions and speeds of all your guests, the positions of the umbrellas, and the time until it starts to rain, find out how many of your guests can at most reach an umbrella. Two guests do not want to share an umbrella, however. 

Input

The input starts with a line containing a single integer, the number of test cases. 
Each test case starts with a line containing the time t in minutes until it will start to rain (1 <=t <= 5). The next line contains the number of guests m (1 <= m <= 3000), followed by m lines containing x- and y-coordinates as well as the speed si in units per minute (1 <= s i <= 3000) of the guest as integers, separated by spaces. After the guests, a single line contains n (1 <= n <= 3000), the number of umbrellas, followed by n lines containing the integer coordinates of each umbrella, separated by a space. 
The absolute value of all coordinates is less than 10000. 

Output

For each test case, write a line containing “Scenario #i:”, where i is the number of the test case starting at 1. Then, write a single line that contains the number of guests that can at most reach an umbrella before it starts to rain. Terminate every test case with a blank line. 

Sample Input

2
1
2
1 0 3
3 0 3
2
4 0
6 0
1
2
1 1 2
3 3 2
2
2 2
4 4

Sample Output

Scenario #1:
2

Scenario #2:
2

你在海边别墅的花园里开派对。聚会非常成功,每个人都来了。这是一个温暖的,阳光明媚的夜晚,和煦的风从海上送来新鲜的,带着咸味的空气。正如你所想象的那样,晚会进行得很顺利。这可能是美好一天的完美结局。
但没有什么是完美的。你的一位客人在做天气预报。他突然喊道:“我知道那微风!这意味着再过几分钟就要下大雨了!“你的客人都穿着他们最好的衣服,真的不想淋湿,所以他们听到这个坏消息时都很害怕。
你准备了几把伞,可以保护几位客人。伞都很小,因为你的客人都有点势利,所以没有客人会和其他客人共用一把伞。雨伞就像你的客人一样,撑在你(巨大的)花园里。更糟的是,你的一些客人跑得不如别人快。
你能帮你的客人尽可能多地在开始下雨前找到一把伞吗?

根据所有客人的位置和速度,雨伞的位置,以及开始下雨的时间,找出有多少客人最多能撑一把伞。然而,两位客人不想共用一把伞。
输入
输入以包含单个整数(测试用例的数量)的行开始。
每个测试用例开始一行包含时间t在几分钟内,直到将开始下雨(1 < = t < = 5)。下一行包含的数量客人m (1 < = m < = 3000),其次是m行包含x - y坐标以及速度每分钟si单位(1 < = s i < = 3000)客人的整数,用空格分开。客人之后,一行包含n (1 <= n <= 3000),伞的数量,后面n行包含每把伞的整数坐标,中间用空格隔开。
所有坐标的绝对值都小于10000。
输出
对于每个测试用例,写一行“Scenario #i:”,其中i是测试用例从1开始的数量。然后,写一行字,表示最多能在下雨前撑到伞的客人人数。用空行结束每个测试用例。
样例输入
2
1
2
1 0 3
3 0 3
2
4 0
6 0
1
2
1 1 2
3 3 2
2
2 - 2
4个4
样例输出
场景# 1:
2

场景# 2:
2

这题说白了就是卡你时间的,要用HK算法 Hopcroft-Karp复杂度O(sqrt(n)*m),问过大四学长,他说他除了这题就没见过有哪题还需要HK算法的,不是很常见,但是咱还是要学啊

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
using namespace std;
 
const int maxn = 3000 + 10;
const int INF = 0x3f3f3f3f;
struct  Person
{
    int x,y;
    int s;
};
struct Umbrella
{
    int x,y;
};
 
Person a[maxn];
Umbrella b[maxn];
vector <int> graph[maxn];//邻接表图
int v1,v2;//左侧点集点的个数,右侧点集点的个数
int visit[maxn];//判断是否访问过
int girl[maxn],boy[maxn];//girl数组每个元素对应一个boy元素,也就是左侧点集的点,boy数组同理
int dx[maxn],dy[maxn];//分别记录左侧点的曾广路距离编号,和右侧点的曾广路距离编号
int dis;//增广路径的距离,是不断变大的
 
//寻找增广路径,每次只寻找当前最短的增广路
bool bfs()
{//注意初始化问题,在此处都得初始化为-1;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    dis = INF;
    queue <int> q;
    for(int i = 0; i < v1; i++)
    {
        if(boy[i] == -1)//将未匹配的点加入队列
        {
            q.push(i);
            dx[i] = 0;
        }
    }
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        if(dx[u] > dis) break;//保证每一层的曾广路路径长度都是相等的,因为每次都要寻找最短的曾广路
        for(int i = 0; i < graph[u].size(); i++)
        {
            int v = graph[u][i];
            if(dy[v] == -1)//也就是说v点还不在一条增广路径中
            {
                dy[v] = dx[u] + 1;//到v点的长度为到u点的长度+1
                if(girl[v] == -1)//如果v点未被匹配
                {
                    dis = dy[v];//此次的增广路径的距离
                }
                else//延长增广路径
                {
                    dx[girl[v]] = dy[v] + 1;
                    q.push(girl[v]);
                }
            }
        }
    }
    return dis != INF;
}
 
bool dfs(int i)
{
    for(int j = 0; j < graph[i].size(); j++)
    {
        int t = graph[i][j];
        if(!visit[t]&&dy[t] == dx[i] + 1)//如果该点没有被访问过并且距离为上一节点+1
        {
            visit[t] = 1;
            if(girl[t] != -1 && dy[t] == dis) continue;
//t已被匹配且已到所有存在的增广路终点,再递归寻找也必无增广路,直接跳过
            if(girl[t] == -1 || dfs(girl[t]))
            {
                girl[t] = i;
                boy[i] = t;
                return true;
            }
        }
    }
    return false;
}
 
int HK()
{
    int cnt = 0;//注意初始化的问题,在这个程序中是-1
    memset(girl,-1,sizeof(girl));
    memset(boy,-1,sizeof(boy));
    while(bfs())
    {//下面类似于匈牙利算法
        memset(visit,0,sizeof(visit));
        for(int i = 0; i < v1; i++)
        {
            if(boy[i] == -1 && dfs(i))
                cnt++;
        }
    }
    return cnt;
}
 
int main()
{
    int kase;
    int num = 0;
    cin >> kase;
    while(kase--)
    {
        for(int i = 0; i < maxn; i++)
        {
            graph[i].clear();
        }
        int  t;
        cin >> t;//输入时间
        int m;
        cin >> m;//人的个数
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].s);//每个人的位置和速度
        }
        int n;
        cin >> n;//雨伞的个数
        for(int i = 0; i < n; i++)
        {
            scanf("%d %d",&b[i].x,&b[i].y);
        }
        v1 = m;
        v2 = n;
        //计算每个人可以到达那些雨伞,建图
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                int dis = (b[j].x - a[i].x)*(b[j].x - a[i].x) + (b[j].y- a[i].y)*(b[j].y- a[i].y);
                if(dis <= a[i].s*t*a[i].s*t)
                {
                    graph[i].push_back(j);
                }
            }
        }
        printf("Scenario #%d:\n",++num);
        cout << HK() << endl << endl;
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值