hdu2389 二分图的匹配HK算法

Rain on your Parade

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 655350/165535 K (Java/Others) Total Submission(s): 1887    Accepted Submission(s): 563

Problem Description
You’re giving a party in the garden of your villa by the sea. The party is a huge success, and everyone is here. It’s a warm, sunny evening, and a soothing wind sends fresh, salty air from the sea. The evening is progressing just as you had imagined. It could be the perfect end of a beautiful day. But nothing ever is perfect. One of your guests works in weather forecasting. He suddenly yells, “I know that breeze! It means its going to rain heavily in just a few minutes!” Your guests all wear their best dresses and really would not like to get wet, hence they stand terrified when hearing the bad news. You have prepared a few umbrellas which can protect a few of your guests. The umbrellas are small, and since your guests are all slightly snobbish, no guest will share an umbrella with other guests. The umbrellas are spread across your (gigantic) garden, just like your guests. To complicate matters even more, some of your guests can’t run as fast as the others. Can you help your guests so that as many as possible find an umbrella before it starts to pour?
Given the positions and speeds of all your guests, the positions of the umbrellas, and the time until it starts to rain, find out how many of your guests can at most reach an umbrella. Two guests do not want to share an umbrella, however.
 
Input
The input starts with a line containing a single integer, the number of test cases. Each test case starts with a line containing the time t in minutes until it will start to rain (1 <=t <= 5). The next line contains the number of guests m (1 <= m <= 3000), followed by m lines containing x- and y-coordinates as well as the speed si in units per minute (1 <= si <= 3000) of the guest as integers, separated by spaces. After the guests, a single line contains n (1 <= n <= 3000), the number of umbrellas, followed by n lines containing the integer coordinates of each umbrella, separated by a space. The absolute value of all coordinates is less than 10000.
 
Output
For each test case, write a line containing “Scenario #i:”, where i is the number of the test case starting at 1. Then, write a single line that contains the number of guests that can at most reach an umbrella before it starts to rain. Terminate every test case with a blank line.
 
Sample Input
2
1
2
1 0 3
3 0 3
2
4 0
6 0
1
2
1 1 2
3 3 2
2
2 2
4 4
 
Sample Output
Scenario #1:
2
 
Scenario #2:
2
 

一、匈牙利算法

算法的思路是不停的找增广轨,并增加匹配的个数,增广轨顾名思义是指一条可以使匹配数变多的路径,在匹配问题中,增广轨的表现形式是一条"交错轨",也就是说这条由图的边组成的路径,它的第一条边是目前还没有参与匹配的,第二条边参与了匹配,第三条边没有..最后一条边没有参与匹配,并且始点和终点还没有被选择过.这样交错进行,显然他有奇数条边.那么对于这样一条路径,我们可以将第一条边改为已匹配,第二条边改为未匹配...以此类推.也就是将所有的边进行"反色",容易发现这样修改以后,匹配仍然是合法的,但是匹配数增加了一对.另外,单独的一条连接两个未匹配点的边显然也是交错轨.可以证明,当不能再找到增广轨时,就得到了一个最大匹配.这也就是匈牙利算法的思路.

 

 

 

二、二分图最大匹配

 

     二分图最大匹配的经典匈牙利算法是由Edmonds在1965年提出的,算法的核心就是根据一个初始匹配不停的找增广路,直到没有增广路为止。

匈牙利算法的本质实际上和基于增广路特性的最大流算法还是相似的,只需要注意两点:

(一)每个X节点都最多做一次增广路的起点;

(二)如果一个Y节点已经匹配了,那么增广路到这儿的时候唯一的路径是走到Y节点的匹配点(可以回忆最大流算法中的后向边,这个时候后向边是可以增流的)。

     找增广路的时候既可以采用dfs也可以采用bfs,两者都可以保证O(nm)的复杂度,因为每找一条增广路的复杂度是O(m),而最多增广n次,dfs在实际实现中更加简短。

 

三、Hopcroft-Karp算法

 

     SRbGa很早就介绍过这个算法,它可以做到O(sqrt(n)*e)的时间复杂度,并且在实际使用中效果不错而且算法本身并不复杂。

     Hopcroft-Karp算法是Hopcroft和Karp在1972年提出的,该算法的主要思想是在每次增广的时候不是找一条增广路而是同时找几条不相交的最短增广路,形成极大增广路集,随后可以沿着这几条增广路同时进行增广。

     可以证明在寻找增广路集的每一个阶段所寻找到的最短增广路都具有相等的长度,并且随着算法的进行最短增广路的长度是越来越长的,更进一步的分析可以证明最多只需要增广ceil(sqrt(n))次就可以得到最大匹配(证明在这里略去)。

     因此现在的主要难度就是在O(e)的时间复杂度内找到极大最短增广路集,思路并不复杂,首先从所有X的未盖点进行BFS,BFS之后对每个X节点和Y节点维护距离标号,如果Y节点是未盖点那么就找到了一条最短增广路,BFS完之后就找到了最短增广路集,随后可以直接用DFS对所有允许弧(dist[y]=dist[x]+1,可以参见高流推进HLPP的实现)进行类似于匈牙利中寻找增广路的操作,这样就可以做到O(m)的复杂度。

     实现起来也并不复杂,对于两边各50000个点,200000条边的二分图最大匹配可以在1s内出解~~

View Code
  1 #include <queue>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <iostream>
  5 using namespace std;
  6 const int MAXN=3005;
  7 const int INF=1<<28;
  8 bool bmap[MAXN][MAXN];
  9 short a[MAXN][3],b[MAXN][2];
 10 bool bmask[MAXN];
 11 int nx,ny,dis;
 12 int cx[MAXN];
 13 int cy[MAXN];
 14 int dx[MAXN];
 15 int dy[MAXN];
 16 bool searchpath()
 17 {
 18     queue<int> Q;
 19     dis=INF;
 20     memset(dx,-1,sizeof(dx));
 21     memset(dy,-1,sizeof(dy));
 22     for(int i=0;i<nx;i++)
 23     {
 24         if(cx[i]==-1)
 25         {
 26             Q.push(i);
 27             dx[i]=0;
 28         }
 29     }
 30     while(!Q.empty())
 31     {
 32         int u=Q.front();
 33         Q.pop();
 34         if(dx[u]>dis) break;
 35         for(int v=0;v<ny;v++)
 36         {
 37             if(bmap[u][v]&&dy[v]==-1)
 38             {
 39                 dy[v]=dx[u]+1;
 40                 if(cy[v]==-1) dis=dy[v];
 41                 else
 42                 {
 43                     dx[cy[v]]=dy[v]+1;
 44                     Q.push(cy[v]);
 45                 }
 46             }
 47         }
 48     }
 49     return dis!=INF;
 50 }
 51 int findpath(int u)
 52 {
 53     for(int v=0;v<ny;v++)
 54     {
 55         if(!bmask[v]&&bmap[u][v]&&dy[v]==dx[u]+1)
 56         {
 57             bmask[v]=1;
 58             if(cy[v]!=-1&&dy[v]==dis)
 59             {
 60                 continue;
 61             }
 62             if(cy[v]==-1||findpath(cy[v]))
 63             {
 64                 cy[v]=u;cx[u]=v;
 65                 return 1;
 66             }
 67         }
 68     }
 69     return 0;
 70 }
 71 void MaxMatch()
 72 {
 73     int res=0;
 74     memset(cx,-1,sizeof(cx));
 75     memset(cy,-1,sizeof(cy));
 76     while(searchpath())
 77     {
 78         memset(bmask,0,sizeof(bmask));
 79         for(int i=0;i<nx;i++)
 80         {
 81             if(cx[i]==-1)
 82             {
 83                 res+=findpath(i);
 84             }
 85         }
 86     }
 87     printf("%d\n",res);;
 88 }
 89 int main()
 90 {
 91     int t,T;
 92     scanf("%d",&T);
 93     for(int q=1;q<=T;q++)
 94     {
 95         scanf("%d",&t);
 96         scanf("%d",&nx);
 97         for(int i=0;i<nx;i++)
 98         {
 99             scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
100         }
101         scanf("%d",&ny);
102         for(int j=0;j<ny;j++)
103         {
104             scanf("%d%d",&b[j][0],&b[j][1]);
105         }
106         memset(bmap,0,sizeof(bmap));
107         for(int i=0;i<nx;i++)
108            for(int j=0;j<ny;j++)
109            {
110                if((b[j][0]-a[i][0])*(b[j][0]-a[i][0])+(b[j][1]-a[i][1])*(b[j][1]-a[i][1])<=t*t*a[i][2]*a[i][2])
111                {
112                    bmap[i][j]=1;
113                    //printf("map[%d][%d]\n",i,j);
114                }
115            }
116         printf("Scenario #%d:\n",q);
117         MaxMatch();
118         printf("\n");
119     }
120 }

 

posted @ 2012-08-30 18:31  _sunshine  阅读(3135)  评论(0编辑  收藏  举报