HDU2389 Rain on your Parade 【二分图最大匹配+HK算法】

HDU2389 链接

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
 

 题意:有n个人,和m把雨伞,每个人都有一个速度,问在t时间内,最大有多少人能找到一把伞。不会出现俩个人打一把伞。

 分析;二分图最大匹配,首先想到匈牙利,但是这回TLE,这时要用HK算法(其实是一种优化的匈牙利算法)

            HK算法是在匈牙利的基础上增加一个BFS,寻找最短的增广路(可以有多条),然后用匈牙利沿着BFS增广的道路,进行增边。

            复杂度为O(sqrt(V)*E) ,二匈牙利算法是O(V*E)(V为点数,E为边数)  (学习HK之前要先学匈牙利算法)


#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
struct edge
{
    int x,y,v;
};
edge a[3003],b[3003];
vector<int> g[3003];
int mx[3003],my[3003],dx[3003],dy[3003],dis,n,m;
bool vis[3003];
int bfs()
{
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    queue<int> que;
    for(int i=1;i<=n;i++)
        if(mx[i]==-1)
    {
        que.push(i);
        dx[i]=0;
    }
    while(!que.empty())
    {
        int x=que.front();que.pop();
        if(dx[x]>dis)break;  //每次找到长度为dis增广路后跳出循环
        for(int i=0;i<g[x].size();i++)
        {    int y=g[x][i];
             if(dy[y]!=-1)continue;

            dy[y]=dx[x]+1;
            if(my[y]==-1)dis=dy[y]; //找到增广路后更新最小值
            else
            {
                dx[my[y]]=dy[y]+1;
                que.push(my[y]);
            }
        }
    }
    return dis!=INF;
}
int dfs(int x)
{
    for(int i=0;i<g[x].size();i++)
    {int y=g[x][i];
       if(vis[y]||dy[y]!=dx[x]+1)continue; //要沿着BFS增广的路
        vis[y]=true;
        if(my[y]!=-1&&dy[y]==dis)continue;
        if(my[y]==-1||dfs(my[y]))
        {
            my[y]=x;
            mx[x]=y;
            return 1;
        }
    }
    return 0;
}
int max_macth()
{
    int ret=0;
    memset(my,-1,sizeof(my));
    memset(mx,-1,sizeof(mx));
    while(bfs())
    {
        memset(vis,false,sizeof(vis));
        for(int i=1;i<=n;i++)
            if(mx[i]==-1&&dfs(i))ret++;
    }
    return ret;
}
int len(int i,int j)
{
    return (a[i].x-b[j].x)*(a[i].x-b[j].x)+(a[i].y-b[i].y)*(a[i].y-b[j].y);
}
int main()
{
    int tat,t,cas=1;
    scanf("%d",&tat);
    while(tat--)
    {
        scanf("%d",&t);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            g[i].clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);
            a[i].v*=t;
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&b[i].x,&b[i].y);

        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            if(len(i,j)<=a[i].v*a[i].v)
                g[i].push_back(j);
            printf("Scenario #%d:\n",cas++);
            printf("%d\n\n",max_macth());
    }
    return 0;
}



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值