Hdu 3289 Rain on your Parade (二分图匹配 Hopcroft-Karp)

题目链接:

  Hdu 3289 Rain on your Parade

题目描述:
  有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 }
posted @ 2015-08-03 21:07  罗茜  阅读(168)  评论(0编辑  收藏  举报