HDU2389Rain on your Parade(二分图最大匹配之Hopcroft-Karp)

来源:互联网 发布:淘宝退款骗局过程 编辑:程序博客网 时间:2024/05/19 15:40

大意:在一个二维坐标系上有nx个人和ny把伞,每个人都有自己的移动速度,问有多少人可以再tmin内移动到不同的雨伞处(不允许两个人共用一把伞)。

思路:很容易可以看出,这是一个二分图模型,雨伞和人一一对应,典型的匹配问题,而又要求最大,所以是二分最大匹配问题,再看看题目的数据量,nx:3000,ny:3000,极限情况下有9000000条边,很明显,匈牙利算法可能会TLE,所以为了降低时间复杂度,我们由每次寻找一条增广路径扩展到寻找多条增广路径,这就跟Dinic与连续增广路的关系很相似。

如何建图呢?只要满足dist(a[i], a[j]) <= si*T的点连一条边即可。

介绍一下Hopcroft-Karp算法,这种算法可以多次寻找增广路径,这样迭代的次数最多为2n^0.5,所以算法优化到了O(n^0.5*m)。


算法详解:http://ws.nju.edu.cn/courses/gt/5.pdf


注意:本模板来自kuangbin模板,该题使用邻接矩阵存的图,且二部图左右点集下标从0开始

#include<stdio.h>#include<queue>#include<iostream>#include<string.h>#include<math.h>using namespace std;#define eps 1e-6const int MAXN=3005;const int INF=1<<28;int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny;int dx[MAXN],dy[MAXN],dis;bool vst[MAXN];struct Node1{    int x,y,s;}guests[MAXN];struct Node2{    int x,y;}um[MAXN];double distance(Node1 a,Node2 b){    double x=a.x-b.x;    double y=a.y-b.y;    return sqrt(x*x+y*y);}bool searchP(){    queue<int>Q;    dis=INF;    memset(dx,-1,sizeof(dx));    memset(dy,-1,sizeof(dy));    for(int i=0;i<Nx;i++)        if(Mx[i]==-1)        {            Q.push(i);            dx[i]=0;        }    while(!Q.empty())    {        int u=Q.front();        Q.pop();        if(dx[u]>dis)  break;        for(int v=0;v<Ny;v++)            if(g[u][v]&&dy[v]==-1)            {                dy[v]=dx[u]+1;                if(My[v]==-1)  dis=dy[v];                else                {                    dx[My[v]]=dy[v]+1;                    Q.push(My[v]);                }            }    }    return dis!=INF;}bool DFS(int u){    for(int v=0;v<Ny;v++)       if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1)       {           vst[v]=1;           if(My[v]!=-1&&dy[v]==dis) continue;           if(My[v]==-1||DFS(My[v]))           {               My[v]=u;               Mx[u]=v;               return 1;           }       }    return 0;}int MaxMatch(){    int res=0;    memset(Mx,-1,sizeof(Mx));    memset(My,-1,sizeof(My));    while(searchP())    {        memset(vst,0,sizeof(vst));        for(int i=0;i<Nx;i++)          if(Mx[i]==-1&&DFS(i))  res++;    }    return res;}int main(){    int n,m,t,i,j;    int T,iCase=0;    scanf("%d",&T);    while(T--)    {        iCase++;        scanf("%d",&t);        scanf("%d",&m);        for(i=0;i<m;i++)           scanf("%d%d%d",&guests[i].x,&guests[i].y,&guests[i].s);        scanf("%d",&n);        for(i=0;i<n;i++)           scanf("%d%d",&um[i].x,&um[i].y);        Nx=m;Ny=n;        memset(g,0,sizeof(g));        for(i=0;i<m;i++)        {           for(j=0;j<n;j++)           {               if(distance(guests[i],um[j])/guests[i].s-t<eps)               {                   g[i][j]=1;               }           }        }        printf("Scenario #%d:\n%d\n\n",iCase,MaxMatch());    }    return 0;}


阅读全文
0 0