Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=2389
【前言】
做个二分图的专题。
遇到这道顶点数3000的题目。
用匈牙利邻接表、邻接矩阵,以及匈牙利非递归版本交了三次,均TLE。
然后找到解题报告,说是HK算法。
网上介绍HK算法的资料挺多,但讲解的挺少,拼凑着突然觉悟了。
【思路】
二分图的思路。但用的是Hopcroft_Karp算法。
匈牙利和HK算法都可以解决二分图最大匹配。
前者复杂度O(n*e),后者O(sqrt(n)*e)。
匈牙利算法每次调用find()函数增广的时候,所形成的搜索路径都像是一棵树,也存在很多重新搜索的情况。
而HK算法在进行find()之前先进行一次bfs()的运算,为每个结点标记一个层次。
当用find()进行搜索的时候,只向那些比自己标号大1的点进行搜索,因为对不比自己大1的点进行的搜索是重复的。
不明白的看一下代码然后再思考一下应该就会的了。HK算法并不难掌握。
【代码】
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3000;//左端点个数
const int maxm = 3000;//右端点个数
vector<int>head[maxn+5];//头指针
int lx[maxn+5], ly[maxm+5];//左右端点对应的匹配
int hx[maxn+5], hy[maxm+5];//左右端点对应的层
int q[maxn+5];//bfs所用的队列
void init(int n, int m)
{
int i;
for (i=0; i<=n; i++)
{
head[i].clear();
lx[i] = -1;
}
for (i=0; i<=m; i++)
{
ly[i] = -1;
}
}
void insert_edge(int from, int to)
{
head[from].push_back(to);
}
bool bfs(int n, int m)
{
int i, j, k;
bool flag = false;
int s, e;
s = e = 0;
for (i=1; i<=n; i++)
{
if (lx[i]==-1)
q[s++] = i;
}
for (i=1; i<=n; i++) hx[i] = 0;
for (i=1; i<=m; i++) hy[i] = 0;
while(e<s)
{
k = q[e];
for (i=0; i<head[k].size(); i++)
{
j = head[k][i];
if (hy[j]==0)
{
hy[j] = hx[k]+1;
if (ly[j]==-1)
{
flag = true;
}
else
{
hx[ly[j]] = hy[j] + 1;
q[s++] = ly[j];
}
}
}
e++;
}
return flag;
}
bool find(int v)
{
int i, j;
for (i=0; i<head[v].size(); i++)
{
j = head[v][i];
if (hy[j]==hx[v]+1)
{
hy[j] = 0;
if (ly[j]==-1 || find(ly[j]))
{
lx[v] = j;
ly[j] = v;
return true;
}
}
}
return false;
}
int Hopcroft_Karp(int n, int m)
{
int ans = 0;
int i;
while(bfs(n, m))
{
for (i=1; i<=n; i++)
{
if (lx[i]==-1 && find(i)) ans++;
}
}
return ans;
}
struct man
{
int x;
int y;
int v;
}gue[maxn+5];
struct unbrella
{
int x;
int y;
}unb[maxm+5];
inline int dist2(man a, unbrella b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int main()
{
int t, index;
int n, m, time;
int i, j;
double s, k;
scanf("%d", &t);
for (index=1; index<=t; index++)
{
scanf("%d", &time);
scanf("%d", &n);
for (i=1; i<=n; i++) scanf("%d %d %d", &gue[i].x, &gue[i].y, &gue[i].v);
scanf("%d", &m);
for (i=1; i<=m; i++) scanf("%d %d", &unb[i].x, &unb[i].y);
init(n, m);
for (i=1; i<=n; i++)
{
k = 1.0*time*gue[i].v;
k *= k;
for (j=1; j<=m; j++)
{
s = dist2(gue[i], unb[j]);
if (s<=k) insert_edge(i, j);
}
}
printf("Scenario #%d:\n", index);
printf("%d\n\n", Hopcroft_Karp(n, m));
}
return 0;
}