HDU2389 Rain on your Parade 二分图匹配——Hopcroft_Karp算法

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


 

你可能感兴趣的:(HDU2389 Rain on your Parade 二分图匹配——Hopcroft_Karp算法)