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;
}