POJ3041 二分圖最大匹配(網絡流算法)

這題可以先構造一個二分圖,它的|X|=|Y|=N,每當輸入一個數對(x,y)時,連接一條x->y的邊,求最小點覆蓋即可。

最小點覆蓋:對於一個二分圖中的每一條邊(u,v)都選其中一個頂點(多條邊可以選同一點),使得選擇的所有點的集合(無重複)元素的數量最小。——我想我已經解釋地很清楚了……

最小點覆蓋相當於最大匹配(證明見《算法藝術與信息學競賽》,《算法導論》……),最大匹配我是用網絡流(弱智辦法)求的,附屬代碼:

#include <cstdio>
#include <string.h>
#include <algorithm>
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;i<bot;i++)
    {
        tmp=Q[i];
        for(edge *p=S[tmp];p;p=p->next)
            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 && tot<alpha;p=p->next)
        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;
}


發佈了26 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章