hdu 4619 匈牙利算法 求最大匹配 2013 Multi-University Training Contest 2

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


当时我不会匈牙利,我的傻X队友不会建图,当时没做出,现在会了匈牙利,这题就成了水题。

15ms AC

首先明确理解二分图匹配:


给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配.
选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem)

这样思考:水平的骨牌与竖直的骨牌有重合,现在要消除重合,所谓消除重合,就是两个有重合的只取一个。

把水平的骨牌当做点集A中的点,竖直的骨牌当做点集B中的点,A 和B 有重合的建立边,则边的 两个顶点只要一个。然后骨牌个数之和-匹配数就是Ans

好像还是解释的不清...以后再来修改吧

下面贴代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1100

int mat[N][N];
int cx[N],cy[N];
bool vis[N];

int n,m;

struct node{
    int x,y;
};

node x[N],y[N];

int path(int u)
{
    int v;
    for(v=0;v<m;v++)
    {
        if(mat[u][v]&&!vis[v])
        {
            vis[v]=1;
            if(cy[v]==-1||path(cy[v]))
            {
                cx[u]=v;
                cy[v]=u;
                return 1;
            }
        }
    }
    return 0;
}

int maxmatch()
{
    int i,res=0;

    memset(cx,-1,sizeof(cx));
    memset(cy,-1,sizeof(cy));
    for(i=0;i<n;i++)
        if(cx[i]==-1)
        {
            memset(vis,0,sizeof(vis));
            res+=path(i);
        }

    return res;
}

int main()
{
    //freopen("hdu 4619.txt","r",stdin);
    int i,j,xx,yy;

    while(scanf("%d%d",&n,&m),n+m)
    {
        for(i=0;i<n;i++)
            scanf("%d%d",&x[i].x,&x[i].y);
        for(i=0;i<m;i++)
            scanf("%d%d",&y[i].x,&y[i].y);

        /*建图*/
        memset(mat,0,sizeof(mat));
        for(i=0;i<n;i++)
        {
            xx=x[i].x;
            yy=x[i].y;
            for(j=0;j<m;j++)
            {
                /*这里y[j].y我写成y[i].y  一直Wa  Wa了几个小时啊........*/
                if((xx==y[j].x&&yy==y[j].y)||((xx+1)==y[j].x&&yy==y[j].y)||(xx==y[j].x&&yy==(y[j].y+1))||((xx+1)==y[j].x&&yy==(y[j].y+1)))mat[i][j]=1;
            }
        }

        printf("%d\n",m+n-maxmatch());
    }

    return 0;
}


你可能感兴趣的:(hdu 4619 匈牙利算法 求最大匹配 2013 Multi-University Training Contest 2)