【Step1】【二分图匹配】模版讲解

前言

二分图匹配问题是各类比赛的热门内容。涉及到的算法有:二分图最大匹配,二分图最佳匹配,König定理(最小覆盖问题)的证明与应用等等,但这些算法的根源在于匈牙利算法深透理解。本文只是简单的,通俗易懂的讲一讲二分图匹配使用匈牙利算法的模版,而理解了这个之后,就需要再去度娘那里看看其它的论文。

二分图

二分图,就是说在一个图中,将所有点分成两堆。如果所有的边的两个端点都分别在两堆中,这个图就是二分图。

二分图最大匹配

在所有的边中找若干的边,使得所选的边两两之间没有公共的端点。求最大的边数。

 

匈牙利算法模版

为了生动形象,我们将第一个集合每个点叫做公牛,另一个集合的点叫做母牛。这样这道题就转化成公牛找母牛的■■■■

首先,我们考虑贪心。如果公牛x和母牛y可以匹配,而且母牛y还没有匹配。那么直接匹配。

但是,如果公牛x和母牛y可以匹配但是母牛y和公牛z已经匹配。那么我们考虑这种情况:

如图,红边表示z和y连在一起。但是对于这四个点,我们明显可以找到一种更优的匹配。

我们发现,从第一种匹配的左下点开始,沿着:没选-选-没选的一条路径,将这条路径反向,我们的答案就能+1。

这样的(没选-选-没选……以没选开头和结束)路径叫做“增广路”,我们解决二分图匹配的过程,就是求增广路的过程。

bool find_muniu(int k)
{
   for(int i=1;i<=m;i++)  
      if (map[k][i]==true)  
         if (chw[i]==true)
         {
            chw[i]=false; 
            if ( match[i]==0 || find_muniu(match[i])==true ) 
            {
                match[i]=k;
                return true; 
            }
         }
   return false;
}

  我们每次枚举我们的公牛(k),然后让它去找匹配。

如果当前母牛没有被占据,就直接匹配。如果被占据,就让匹配了这头母牛的公牛再去找未匹配的母牛。(这个步骤就是找增广路的过程。

唯一要注意的是chw数组,表示这个母牛在这次公牛的寻找匹配中有没有出现过。如果它本来就是增广路的一部分,我们走回来了,很明显不合法,而且会死循环。

 

这样子我们的代码就呼之欲出了

二分图匹配模版

#include<cstdio>
#include<cstdlib>
#include<cstring>
int n,m;
int first[205];
int len=0;
bool map[205][205];
int match[205];
bool chw[205];
bool find_mn(int x)
{
    for(int i=1;i<=m;i++)
    {
        if(map[x][i]==true && chw[i]==true)
        {
            chw[i]=false;
            if(match[i]==0 || find_mn(match[i])==true)
            {
                match[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
    memset(first,0,sizeof(first));
    memset(map,false,sizeof(map));
    len=0;
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        for(int j=1;j<=x;j++)
        {
            int soy;
            scanf("%d",&soy);
            map[i][soy]=true;
        }
    }
    int ans=0;
    memset(match,0,sizeof(match));
    for(int i=1;i<=n;i++)//枚举公牛
    {
        memset(chw,true,sizeof(chw));
        if(find_mn(i)==true)ans++;
    }
    printf("%d\n",ans);
}
    return 0;
}
View Code

二分图的建图和对应的König定理,让这个专题变得很复杂。在之后的博客中再说吧。

 

posted @ 2017-11-14 13:17  ZSYZlhy  阅读(238)  评论(0编辑  收藏  举报