您的位置:首页 > 大数据 > 人工智能

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

2017-07-31 18:35 495 查看
HDU2389 链接

[align=left]Sample Input[/align]

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

 

[align=left]Sample Output[/align]

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("
4000
%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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: