POJ3041 二分图最大匹配(网络流算法)

这题可以先构造一个二分图,它的|X|=|Y|=N,每当输入一个数对(x,y)时,连接一条x->y的边,求最小点覆盖即可。

最小点覆盖:对于一个二分图中的每一条边(u,v)都选其中一个顶点(多条边可以选同一点),使得选择的所有点的集合(无重复)元素的数量最小。——我想我已经解释地很清楚了……

最小点覆盖相当于最大匹配(证明见《算法艺术与信息学竞赛》,《算法导论》……),最大匹配我是用网络流(弱智办法)求的,附属代码:

#include 
#include 
#include 
using namespace std;
const int NMax=1500;
struct edge
{
    int num,len;
    edge *next,*rev;
}*S[NMax],pool[10000];
int N,K,nn,L;
void Build(int x,int y,int z)
{
    edge *p=&pool[L++],*q=&pool[L++];
    p->num=y; p->len=z; p->next=S[x];
    q->num=x; q->len=0; q->next=S[y];
    p->rev=q; q->rev=p;
    S[x]=p; S[y]=q;
}
int Q[NMax],level[NMax];
bool makelevel()
{
    int tmp;
    memset(level,-1,sizeof(level));
    Q[0]=0;
    level[0]=0;
    for(int i=0,bot=1;inext)
            if(p->len>0 && level[p->num]==-1)
                level[Q[bot++]=p->num]=level[tmp]+1;
    }
    return level[nn]!=-1;
}
int DFS(int a,int alpha)
{
    int tot=0,tmp;
    if(a==nn) return alpha;
    for(edge *p=S[a];p && totnext)
        if(p->len>0 && level[p->num]==level[a]+1)
            if(tmp=DFS(p->num,min(alpha-tot,p->len)))
            {
                tot+=tmp;
                p->len-=tmp;
                if(p->rev!=NULL) p->rev->len+=tmp;
            }
    if(!tot) level[a]=-1;
    return tot;
}
int main()
{
    int x,y;
    scanf("%d%d",&N,&K);
    nn=N*2+1;
    for(int i=1;i<=K;i++)
    {
        scanf("%d%d",&x,&y);
        Build(x,N+y,1);
    }
    for(int i=1;i<=N;i++)
    {
        Build(0,i,1);
        Build(N+i,nn,1);
    }
    int ans=0,tmp;
    while(makelevel())
        while(tmp=DFS(0,(~0u>>1)))
            ans+=tmp;
    printf("%d\n",ans);
    return 0;
}


你可能感兴趣的:(图论)