码迷,mamicode.com
首页 > 其他好文 > 详细

二分图匹配

时间:2017-12-09 12:59:07      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:情况   技术分享   next   har   continue   基本   部分   lin   algo   

  这两个星期一直没什么时间上机,最近学了学二分图,这里就来记录一下。

------------------------------------------------------------分割线

  先讲讲一些基本概念:

  二分图:在一个图中,如果图中的点可以被分为两个部分,两部分之间有若干条边相连,且每个部分的点之间无边相连,则该图是一个二分图。由此可以很容易知道,二分图绝对是一个无环图。

  匹配:图论中,一个“匹配”是一个边的集合,其中任意两条都没有公共定点。由此衍生出一些其他的概念,匹配点,匹配边,未匹配点,未匹配边,定义显而易见就不多赘述了。

  最大匹配:一个二分图中包含的边数最大的一个匹配就是这个二分图的最大匹配。一般二分图的问题经常会涉及到最大匹配,所以这也是学习二分图的一个重点。

  完美匹配:如果在一个二分图中,存在一个匹配使得所有点都是匹配点,则这个匹配称为这个二分图的完美匹配。可知,一个二分图的完美匹配一定也是这个二分图的一个最大匹配。

  技术分享图片  技术分享图片  技术分享图片  技术分享图片

  如上图,图一是一个二分图,但从外表并不明显,可以转换成图二的样式。图三是这个二分图的一个匹配(红线部分),图四则是它的最大匹配,也是完美匹配。

  讲完基本概念,来说说解决二分图最大匹配的常用算法——匈牙利算法。

  首先讲讲两个概念,交替路和增广路。

  如右图技术分享图片

  交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。

  增广路:从一个未匹配点出法,走交替路,如果途径一个未匹配点(非出发点),则该条交替路称为一个增广路。如下图是上图的一个增广路展开后的情况

  技术分享图片

  由这两个概念可以知道,如果一个二分图中存在增广路则最大匹配一定比当前找到的匹配大。如上图,找到的增广路中有两条匹配边4-8和1-6,则现在可以增加为三条9-4和8-1和6-2。匈牙利算法的主体思想大致就是这样,不停地寻找增广路,如果可以找到,则当前答案ans++,直到找不到增广路为止,正确性很容易证明。

  一般匈牙利算法有BFS和DFS两种方法。下面放上洛谷模板题的dfs算法:

  

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
const int N=2018;
const int M=1000010;
using namespace std;
int n,m,en,match[N];
int head[N],size,ans;
bool check[N];
struct Node{
int to,next;
}edge[M];
inline int read()
{
    char ch=getchar();int num=0;bool flag=false;
    while(ch<0||ch>9){if(ch==-)flag=true;ch=getchar();}
    while(ch>=0&&ch<=9){num=num*10+ch-0;ch=getchar();}
    return flag?-num:num;
}
inline int add(int x,int y)
{
    edge[++size].to=y;
    edge[size].next=head[x];
    head[x]=size;
}
void ready()
{
    n=read();m=read();en=read();
    memset(head,-1,sizeof(head));
    for(int i=1;i<=en;i++){
    int x=read();int y=read();
    if(x>n||y>m)continue;
    add(x,y+n);add(y+n,x);
    }
    memset(match,-1,sizeof(match));
}
inline bool dfs(int u)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!check[v]){
            check[v]=true;
            if(match[v]==-1||dfs(match[v]))
            {
                match[u]=v;match[v]=u;
                return true;
            }
        }
    }
    return false;
}
void work()
{
    for(int i=1;i<=n;i++){
        if(match[i]==-1){
            memset(check,0,sizeof(check));
            if(dfs(i))ans++;
        }
    }
    cout<<ans<<"\n";
}
int main()
{
    ready();work();return 0;
}

   一般来说,数据小的时候,bfs比dfs要优得多,而大数据两者复杂度几乎相同,这里我就不再放bfs的代码了,网上很多大佬们都写的比我好,都可以参考。

  OI是一条漫长的路,未来还很漫长。

二分图匹配

标签:情况   技术分享   next   har   continue   基本   部分   lin   algo   

原文地址:http://www.cnblogs.com/cytus/p/8010966.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!