hdu 2389 Rain on your Parade
http://acm.hdu.edu.cn/showproblem.php?pid=2389
Hopcroft-Karp算法是二分匹配的一个十分快捷的算法,相对于匈牙利算法在时间上有了相当大的改进!
hdu 2389 这题我是前两天尝试做二分匹配的题的时候遇见的,当时我看到点的规模达到3000个,我就想到这题不能用匈牙利算法来过。不过当时我还不会hk算法,所以我只好当作练习匈牙利算法,打了一遍交上去!回来的结果必然是TLE。然后,我只好看了一下题解,才发现hk算法这神级速度的二分匹配算法!
我想说一下的是,在图论的算法中,用的最多的优化方式就是将dfs转化成bfs,用队列,优先队列,亦或是单调队列来加快算法的工作速度。
这题如果是用dfs,那么搜n个点,e条边,最高的复杂度可以达到O(n^3)。其中的原因是搜索n个点可能出现每次都要搜索大量的边,然而,这些被搜索的边很多都是没必要的。于是,在匈牙利算法的基础上,在dfs前用bfs的方法来预留可能匹配的边,然后dfs搜索的时候就可以减少不必要的搜索,从而加快搜索速度!
代码如下(8.16修改):
View Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <vector> 5 6 using namespace std; 7 const int maxn = 3001; 8 9 int dx[maxn], dy[maxn], mx[maxn], my[maxn]; 10 int q[maxn << 1], qh, qt; 11 vector<int> rel[maxn]; 12 struct point{ 13 int x, y; 14 int v; 15 }guest[maxn]; 16 17 int bfs(int n, int m){ 18 bool ret = false; 19 20 qh = qt = 0; 21 for (int i = 1; i <= m; i++){ 22 dy[i] = 0; 23 } 24 for (int i = 1; i <= n; i++){ 25 dx[i] = 0; 26 if (mx[i] == -1){ 27 q[qt++] = i; 28 } 29 } // reset status of x&y-set using array dx & dy and queue-in the x-nodes which are not matched 30 31 while (qh != qt){ // set distance of every pair of x,y-nodes 32 int cur = q[qh++]; 33 34 for (int i = 0; i < rel[cur].size(); i++){ 35 int t = rel[cur][i]; 36 37 if (!dy[t]){ 38 dy[t] = dx[cur] + 1; 39 if (my[t] == -1){ 40 ret = true; 41 } 42 else{ 43 dx[my[t]] = dy[t] + 1; 44 q[qt++] = my[t]; // 前一个版本将my[t]写成t水过去了 45 } // if t is matched, let the x-node matched with t queue-in and find its other adjacent y-nodes 46 } 47 } 48 } 49 50 return ret; 51 } 52 53 bool dfs(int cur){ 54 for (int i = 0; i < rel[cur].size(); i++){ 55 int t = rel[cur][i]; 56 57 if (dy[t] == dx[cur] + 1){ // if satisfied the pair distance, go deeper 58 dy[t] = 0; 59 if (my[t] == -1 || dfs(my[t])){ 60 my[t] = cur; 61 mx[cur] = t; 62 63 return true; 64 } // find a satisfied pair 65 } 66 } 67 68 return false; 69 } 70 71 int hk(int n, int m){ 72 int cnt = 0; 73 74 for (int i = 1; i <= n; i++){ 75 mx[i] = my[i] = -1; 76 } 77 while (bfs(n, m)){ 78 for (int i = 1; i <= n; i++){ 79 if (mx[i] == -1 && dfs(i)){ 80 cnt++; 81 } 82 } 83 } 84 85 return cnt; 86 } 87 88 bool judge(point g, point u, int t){ 89 int x = g.x - u.x; 90 int y = g.y - u.y; 91 int s = g.v * t; 92 93 if (x * x + y * y <= s * s){ 94 return true; 95 } 96 97 return false; 98 } 99 100 void deal(int c){ 101 int n, m, t; 102 103 scanf("%d", &t); 104 scanf("%d", &n); 105 for (int i = 1; i <= n; i++){ 106 scanf("%d%d%d", &guest[i].x, &guest[i].y, &guest[i].v); 107 rel[i].clear(); 108 } 109 scanf("%d", &m); 110 for (int i = 1; i <= m; i++){ 111 scanf("%d%d", &guest[0].x, &guest[0].y); 112 for (int j = 1; j <= n; j++){ 113 if (judge(guest[j], guest[0], t)){ 114 rel[j].push_back(i); 115 } 116 } 117 } 118 119 printf("Scenario #%d:\n%d\n\n", c, hk(n, m)); 120 } 121 122 int main(){ 123 int n; 124 125 #ifndef ONLINE_JUDGE 126 freopen("in", "r", stdin); 127 #endif 128 129 scanf("%d", &n); 130 for (int i = 1; i <= n; i++) 131 deal(i); 132 133 return 0; 134 }
修改内容包括:
1.删除记录入队情况的bool数组,因为元素不会入队两次
2.在hk函数中,dfs前必须判断该边是否已经匹配
hk算法:http://www.cnblogs.com/LyonLys/archive/2012/08/11/Hopcroft_Karp_Lyon.html
——written by Lyon