HDU 4619 —— Warm up 2(二分图最大匹配)

来源:互联网 发布:提督的决断 知乎 编辑:程序博客网 时间:2024/05/17 23:02

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4619

最近学了二分匹配,这块我是看kuangbin大神的文章的:http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657446.html

个人觉得他博客的文章很赞,很多总结也写得很好,强力推荐!

平面上有很多1X2的多米诺骨牌,横放或竖放,相同方向的不会重叠。现在要取走一些,使得剩下的两两没有重叠,问最多能剩下多少个。

有两种考虑的方法,一种是每块牌看作一个点,有重叠到的两块骨牌之间就连一条线,那么问题就是求最大独立集,最大独立集=总点数-最大匹配。

另一种就是将每个格点(每个骨牌占据两个格点)当作一个点,同一块骨牌覆盖到的格点就连一条线,那么问题就是对这些格点求一个最大匹配。

前者可以看作有N+M个点,后者最多是2*(N+M)个点。

但前者构图的时候每个骨牌都要去遍历另一种骨牌,构图的复杂度是O(NM),这种做法在kuangbin的博客上也有;

后者则只是在读入骨牌的时候直接构图,不用考虑其他骨牌,复杂度是O(N+M),但相对的后期处理的点就比较多,我采用的是这种;

对于每个坐标(x,y),因为0<=x<=100 ,0<=y<=100,所以每个坐标可以映射成一个数z=x*101+y

用一个f[z]来记录这块格点对应的编号,从1开始,因为N和M都不超过1000,所以覆盖到的最多4000个,如果不整理编号总共要101*101个点,但其中很多是空白的。

然后就是构图求最大匹配,最后的答案记得除以2。

二分匹配用的是Hopcroft-Carp算法。

#include<cstdio>#include<cstring>#include<vector>#include<queue>using namespace std;#define pb push_back#define maxn 4001const int inf = 0x7fffffff;inline void IN(int& x){    char c=getchar();    while(c<48 || c>57) c=getchar();    x=0;    while(c>=48 && c<=57){        x=x*10+c-48;        c=getchar();    }}vector<int> V[maxn];int n, dis;int f[20000];int dx[maxn], dy[maxn], Mx[maxn],  My[maxn];bool vis[maxn];bool search(){    queue<int> Q;    dis=inf;    memset(dx,-1,sizeof(dx));    memset(dy,-1,sizeof(dy));    for(int i=1; i<=n; i++){        if(Mx[i]==-1){            dx[i]=0; Q.push(i);        }    }    while(!Q.empty()){        int u=Q.front(); Q.pop();        if(dx[u]>dis)   break;        for(int i=0; i<V[u].size(); i++){            int j=V[u][i];            if(dy[j]!=-1)   continue;            dy[j] = dx[u]+1;            if(My[j]==-1)   dis=dy[j];            else{                dx[My[j]] = dy[j]+1;                Q.push(My[j]);            }        }    }    return (dis!=inf);}bool dfs(int x){    for(int i=0; i<V[x].size(); i++){        int j= V[x][i];        if(vis[j] || dy[j]!=dx[x]+1)  continue;        vis[j]=1;        if(My[j]!=-1 && dy[j]==dis) continue;        if(My[j]==-1 || dfs(My[j])){            My[j]=x; Mx[x]=j;            return 1;        }    }    return 0;}int MaxMatch(){    int ans=0;    memset(Mx,-1,sizeof(Mx));    memset(My,-1,sizeof(My));    while(search()){        memset(vis,0,sizeof(vis));        for(int i=1; i<=n; i++){            if(Mx[i]==-1 && dfs(i)) ans++;        }    }    return ans;}int main(){    while(1){        int a, b, x, y, z1, z2;        IN(a); IN(b);        if(!(a||b)) break;        memset(f,0,sizeof(f));        n=0;        while(a--){            IN(x); IN(y);            z1 = x*101+y;            z2 = z1+101;            if(!f[z1]){                f[z1]=++n;                V[n].clear();            }            z1 = f[z1];            if(!f[z2]){                f[z2]=++n;                V[n].clear();            }            z2 = f[z2];            V[z1].pb(z2);            V[z2].pb(z1);        }        while(b--){            IN(x); IN(y);            z1 = x*101+y;            z2 = z1+1;            if(!f[z1]){                f[z1]=++n;                V[n].clear();            }            z1 = f[z1];            if(!f[z2]){                f[z2]=++n;                V[n].clear();            }            z2 = f[z2];            V[z1].pb(z2);            V[z2].pb(z1);        }        printf("%d\n", MaxMatch()>>1);    }    return 0;}


0 0
原创粉丝点击