学习笔记----二分图的最大匹配

今天了解了一下二分图的最大匹配,学习了一下,乘着自己还记忆比较深刻,赶紧的记下来,以便于复习与查看。

先说一下学习的出处主要是在网上看的博客与同学讲解、、感谢一下博主的分享

http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657446.html  博客园kuangbin

http://xuxiaoqi986.blog.163.com/blog/static/167376398201171710232714/ 网易博客 落飞


先说一下一些基本的定义吧:

1。二部图: 
 如果图G=(V,E)的顶点集何V可分为两个集合X,Y,且满足 X∪Y = V, X∩Y=Φ,则G称为二部图;图G的边集用E(G)表示,点集用V(G)表示。
2。匹配: 
 设M是E(G)的一个子集,如果M中任意两条边在G中均不邻接,则称M是G的一个匹配。M中的—条边的两个端点叫做在M是配对的。    
3。饱和与非饱和: 
  若匹配M的某条边与顶点v关联,则称M饱和顶点v,并且称v是M-饱和的,否则称v是M-不饱和的。 
4。交互道: 
  若M是二分图G=(V,E)的一个匹配。设从图G中的一个顶点到另一个顶点存在一条道路,这条道路是由属于M的边和不属于M的边交替出现组成的,则称这条道路为交互道。 
5。可增广道路: 
  若一交互道的两端点为关于M非饱和顶点时,则称这条交互道是可增广道路。显然,一条边的两端点非饱和,则这条边也是可增广道路。 
6。最大匹配: 
  如果M是一匹配,而不存在其它匹配M',使得|M'|>|M|,则称M是最大匹配。其中|M|表示匹配M的边数。 
7。对称差: 
  A,B是两个集合,定义 A?B = (A∪B)\(A∩B) 
  则A?B称为A和B的对称差。 
  定理:M为G的最大匹配的充要条件是G中不存在可增广道路。 
Hall定理:对于二部图G,存在一个匹配M,使得X的所有顶点关于M饱和的充要条件是:对于 
X的任意一个子集A,和A邻接的点集为T(A),恒有: |T(A)| >= |A|

其中A\B表示集合A和集合B的商集,即属于A且不属于集合B的集合。

(2)定理(依据):

   定理:M为G的最大匹配的充要条件是G中不存在可增广道路。 
Hall定理:对于二部图G,存在一个匹配M,使得X的所有顶点关于M饱和的充要条件是:对于 
X的任意一个子集A,和A邻接的点集为T(A),恒有: |T(A)| >= |A| 
(3)匈牙利算法是基于Hall定理中充分性证明的思想,其——基本步骤:
  1.任给初始匹配M; 
2.若X已饱和则结束,否则进行第3步; 
3.在X中找到一个非饱和顶点x0, 作V1 ← {x0},  V2 ← Φ; 
4.若T(V1) = V2则因为无法匹配而停止,否则任选一点y ∈T(V1)\V2; 
5.若y已饱和则转6,否则做一条从x0 →y的可增广道路P,M←M?E(P),转2; 
6.由于y已饱和,所以M中有一条边(y,z),作 V1 ← V1 ∪{z}, V2 ← V2 ∪ {y}, 转4; 

一些基本的定理:

1。一个二分图中的最大匹配数等于这个图中的最小点覆盖数
König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。
2。最小路径覆盖=最小路径覆盖=|G|-最大匹配数
 在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,
 且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,
 那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.
由上面可以得出:
 1.一个单独的顶点是一条路径;
 2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的
   顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.
 路径覆盖与二分图匹配的关系:最小路径覆盖=|G|-最大匹配数;
3。二分图最大独立集=顶点数-二分图最大匹配
独立集:图中任意两个顶点都不相连的顶点集合。
另付模板一套:(不是原创)

#include
#include
int map[505][505];
int dis[505],m,n,inq[505];
int find(int t)
{
    int i;
    for(i=1; i<=m; i++)
    {
        if(inq[i]==0&&map[t][i])
        {
            inq[i]=1;
            if(dis[i]==-1||find(dis[i]))
            {
                dis[i]=t;
                return 1;
            }
        }
    }
    return 0;
}
int max()
{
    int i,num;
    num=0;
    memset(dis,-1,sizeof(dis));
    for(i=1; i<=n; i++)
    {
        memset(inq,0,sizeof(inq));
        if(find(i))
            num++;
    }
    return num;
}
int main()
{
    int k,a,b;
    while(scanf("%d",&k),k!=0)
    {
        memset(map,0,sizeof(map));
        scanf("%d%d",&n,&m);
        while(k--)
        {
            scanf("%d%d",&a,&b);
            map[a][b]=1;
        }
        printf("%d\n",max());
    }
    return 0;
}


你可能感兴趣的:(学习笔记)