二分图的最大匹配(匈牙利算法)

来源:互联网 发布:广贵交易软件 编辑:程序博客网 时间:2024/06/09 23:30

(算法)二分图的最大匹配(匈牙利算法)

分类: 算法整理 293人阅读 评论(0) 收藏 举报
算法

 先说下二分图的概念吧:二分图是指图可以分成两个点集X和Y,那么任意一条边两个端点分属于不同的点集,也就是说任意一条边的的一个端点在X中,另外一个端点在Y中。并且同一个点集中的任意点之间是没有边相连的,满足这样的性质的图就是二分图。

       匹配是指:在给定的一个二分图G中的一个边的子集构成的集合M,M中的任意两条边都没有公共的顶点,那么M就称为一个匹配。那么匹配中含有边数最多的匹配就是最大匹配。

       下面来说说匈牙利算法是如何求解二分图的最大匹配的吧。

       匈牙利算法是通过不断的找增广路径来扩大匹配集中匹配的边数,我们对左边点集的每一个点找增广路径,直到找不到了增广路径,那么这个时候的匹配就是最大匹配。

       匈牙利算法的基本思想就是这样,如果想要具体了解,自己画个图理解下就行了,很容易理解的。下面我们来说说匈牙利算法是如何实现的吧。

       首先我们需要构建一个二分图,这个随你。之后为了找增广路径,我们需要一个match[i]表示右边点集的i的匹配的左边的点,如果是-1,那么表示还没有找到匹配的点;这个数组在我们找增广路径的时候非常重要。

        其次我们需要一个vis数组,用来表示在每一次找增广路径的时候左边的点是否被访问过,这个是为了防止重复找同一个点而出现错误。

        我们再找增广路径的时候,如果一个点的match[i]==-1,那么我们就找到了一条增广路径,返回1;否则我们继续找,对match[i]进行dfs,如果最终都没有找到增广路径,那么就只好返回零表示没有找到增广路径。

       基于这个思想,我把在POJ上的2239那道题的代码贴上来,匈牙利算法基本都是差不多的,有需要的可以拿过去参考一下。呵呵——

[html] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #define LMAX 310  
  5. #define RMAX 90  
  6. int edge[LMAX][RMAX];  
  7. int vis[RMAX],match[RMAX];  
  8. int RN;//左边的顶点的个数,右边顶点的个数  
  9.   
  10.   
  11. int dfs(int i)  
  12. {  
  13.     int j;  
  14.     for(j=1;j<=RN;j++)  
  15.     {  
  16.         if(edge[i][j]&&vis[j]==0)  
  17.         {  
  18.             vis[j]=1;  
  19.             if(match[j]==-1)  
  20.             {  
  21.                 match[j]=i;  
  22.                 return 1;  
  23.             }  
  24.             else  
  25.             {  
  26.                 if(dfs(match[j]))  
  27.                 {  
  28.                     match[j]=i;  
  29.                     return 1;  
  30.                 }  
  31.             }  
  32.         }  
  33.     }  
  34.     return 0;  
  35. }  
  36.   
  37. int solve(int LN)  
  38. {  
  39.     memset(match,-1,sizeof(match));  
  40.     int i,sum=0;  
  41.     for(i=1;i<=LN;i++)  
  42.     {  
  43.             memset(vis,0,sizeof(vis));  
  44.             if(dfs(i))  
  45.                 sum++;  
  46.     }  
  47.     return sum;  
  48. }  
  49.   
  50. int main()  
  51. {  
  52.     int n,t;  
  53.     int i;  
  54.     int a,b;  
  55.     RN=7*12;  
  56. //    freopen("data.txt","r",stdin);  
  57.     while(scanf("%d",&n)!=EOF)  
  58.     {  
  59.         memset(edge,0,sizeof(edge));  
  60.         for(i=1;i<=n;i++)  
  61.         {  
  62.             scanf("%d",&t);  
  63.             while(t--)  
  64.             {  
  65.                 scanf("%d %d",&a,&b);  
  66.                 edge[i][(a-1)*12+b]=1;  
  67.             }  
  68.         }  
  69.   
  70.         printf("%d\n",solve(n));  
  71.   
  72.     }  
  73.     return 0;  
  74. }