二分图的最大匹配

3个重要结论:

最小点覆盖数: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数
最小路径覆盖=最小路径覆盖=|N|-最大匹配数
用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。
二分图最大独立集=顶点数-二分图最大匹配
在N个点的图G中选出m个点,使这m个点两两之间没有边,求m最大值。
如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数。

例题:

http://poj.org/problem?id=1469  COURSES

有了匈牙利算法的基础,该题就是一道非常简单的题目了:该题给出P门课程,N个学生,问能否从中选出P个学生,使每个学生上不同的课,且每个课程有一个学生。典型的二分图匹配的问题,我们只要计算最大二分图匹配数,如果和课程数相同就输出YES,否则输出NO。

//poj_1469  
/*==================================================*\ 
| 二分图匹配(匈牙利算法DFS 实现) 
| INIT: g[][]邻接矩阵; 
| 优点:实现简洁容易理解,适用于稠密图,DFS找增广路快。 
| 找一条增广路的复杂度为O(E),最多找V条增广路,故时间复杂度为O(VE) 
==================================================*/  
#include<stdio.h>  
#include<memory.h>  
  
bool g[110][310]; //邻接矩阵,true代表有边相连  
bool flag,visit[310];    //记录V2中的某个点是否被搜索过  
int match[310];   //记录与V2中的点匹配的点的编号  
int p,n;   //二分图中左边、右边集合中顶点的数目   
  
// 匈牙利算法  
bool dfs(int u)  
{  
    for (int i = 1; i <= n; ++i)  
    {  
        if (g[u][i] && !visit[i])   //如果节点i与u相邻并且未被查找过  
        {  
            visit[i] = true;   //标记i为已查找过  
            if (match[i] == -1 || dfs(match[i]))   //如果i未在前一个匹配M中,或者i在匹配M中,但是从与i相邻的节点出发可以有增广路径  
            {  
                match[i] = u;  //记录查找成功记录,更新匹配M(即“取反”)  
                return true;   //返回查找成功  
            }  
        }  
    }  
    return false;  
}  
  
int main(void)  
{  
    int i,j,k,t,v,ans;  
    scanf("%d",&t);  
    while (t--)  
    {  
          scanf("%d %d", &p, &n);  
          for (i = 1; i <= p; i++)  
          {  
              for (j = 1; j <= n; j++)  
                  g[i][j] = false;  
          }  
          for (i = 1; i <= n; i++)  
              match[i] = -1;  
          flag = true;  
          for (i = 1; i <= p; i++)  
          {  
              scanf("%d",&k);  
              if (k == 0)  
                 flag = false;  
              while (k--)  
              {  
                    scanf("%d",&v);  
                    g[i][v]  = true;  
              }  
          }  
          if (flag)  
          {  
               ans = 0;  
               for (i = 1; i <= p; i++)  
               {  
                   memset(visit,false,sizeof(visit));   //清空上次搜索时的标记  
                   if( dfs(i) )    //从节点i尝试扩展  
                       ans++;  
               }  
               if (ans == p)  
                   puts("YES");  
               else  
                   puts("NO");  
          }   
          else  
              puts("NO");  
    }  
      
    return 0;  
}  

 

posted on 2017-04-26 20:31  远搏  阅读(189)  评论(0)    收藏  举报

导航