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