Hdu 3289 Rain on your Parade (二分图匹配 Hopcroft-Karp)
题目链接:
题目描述:
有n个客人,m把雨伞,在t秒之后将会下雨,给出每个客人的坐标和每秒行走的距离,以及雨伞的位置,问t秒后最多有几个客人可以拿到雨伞?
解题思路:
数据范围太大,匈牙利算法O(n*m)果断华丽丽的TLE,请教了一下度娘,发现还有一种神算法—— Hopcroft-Karp,然后就get√新技能,一路小跑过了,有一点不明白的是hdu上竟然有人0ms过,这又是什么神姿势(吓哭!!!!!),额.........,扯远了。
Hopcroft-Karp复杂度O(sqrt(n)*m),相比匈牙利算法优化在于,Hopcroft-Karp算法每次可以扩展多条不相交增广路径。
1 #include <iostream> 2 #include <cstring> 3 #include <queue> 4 #include <cmath> 5 #include <cstdio> 6 using namespace std; 7 8 const int maxn = 3000; 9 const int INF = 0x3f3f3f3f; 10 struct node 11 { 12 int to, next; 13 } edge[maxn*maxn+10]; 14 struct point 15 { 16 double x, y, num; 17 }; 18 point p_gue[maxn+5], p_umb[maxn+5]; 19 int head[maxn+5], vis[maxn+5], n, m, tot, dis; 20 int cx[maxn+5], cy[maxn+5], dx[maxn+5], dy[maxn+5]; 21 22 void Add (int from, int to) 23 { 24 edge[tot].to = to; 25 edge[tot].next = head[from]; 26 head[from] = tot ++; 27 } 28 29 bool bfs () 30 {//寻找多条无公共点的最短增广路 31 queue <int> Q; 32 dis = INF; 33 memset (dx, -1, sizeof(dx)); 34 //左边顶点i所在层编号 35 memset (dy, -1, sizeof(dy)); 36 //右边顶点i所在层编号 37 for (int i=1; i<=n; i++) 38 if (cx[i] == -1) 39 { 40 Q.push(i); 41 dx[i] = 0; 42 } 43 while (!Q.empty()) 44 { 45 int u = Q.front(); 46 Q.pop(); 47 if (dx[u] > dis) 48 break; 49 for (int i=head[u]; i!=-1; i=edge[i].next) 50 { 51 int v = edge[i].to; 52 if (dy[v] == -1) 53 { 54 dy[v] = dx[u] + 1; 55 if (cy[v] == -1) 56 dis = dy[v]; 57 else 58 { 59 dx[cy[v]] = dy[v] + 1; 60 Q.push(cy[v]); 61 } 62 } 63 } 64 } 65 return dis != INF; 66 } 67 int dfs (int u) 68 {//寻找路径 69 for (int i=head[u]; i!=-1; i=edge[i].next) 70 { 71 int v = edge[i].to; 72 if (!vis[v] && dy[v] == dx[u]+1) 73 { 74 vis[v] = 1; 75 if (cy[v]!=-1 && dis==dy[v]) 76 continue; 77 if (cy[v]==-1 || dfs(cy[v])) 78 { 79 cy[v] = u; 80 cx[u] = v; 81 return 1; 82 } 83 } 84 } 85 return 0; 86 } 87 int Max_match () 88 {//得到最大匹配数目 89 int res = 0; 90 memset (cx, -1, sizeof(cx)); 91 //左边顶点i所匹配的右边的点 92 memset (cy, -1, sizeof(cy)); 93 //右边顶点i所匹配的左边的点 94 while (bfs ()) 95 { 96 memset (vis, 0, sizeof(vis)); 97 for (int i=1; i<=n; i++) 98 if (cx[i] == -1) 99 res += dfs(i); 100 } 101 return res; 102 } 103 int main () 104 { 105 int cas, t, l = 0; 106 scanf ("%d", &cas); 107 while (cas --) 108 { 109 scanf ("%d %d", &t, &n); 110 for (int i=1; i<=n; i++) 111 { 112 scanf ("%lf %lf %lf", &p_gue[i].x, &p_gue[i].y, &p_gue[i].num); 113 p_gue[i].num *= t; 114 } 115 116 scanf ("%d", &m); 117 for (int i=1; i<=m; i++) 118 scanf ("%lf %lf", &p_umb[i].x, &p_umb[i].y); 119 120 memset (head, -1, sizeof(head)); 121 tot = 0; 122 for (int i=1; i<=n; i++) 123 for (int j=1; j<=m; j++) 124 { 125 double x = p_gue[i].x - p_umb[j].x; 126 double y = p_gue[i].y - p_umb[j].y; 127 double num = sqrt (x*x + y*y); 128 if (num <= p_gue[i].num) 129 Add (i, j); 130 } 131 printf ("Scenario #%d:\n%d\n\n", ++l, Max_match()); 132 } 133 return 0; 134 }
本文为博主原创文章,未经博主允许不得转载。