先说下二分图的概念吧:二分图是指图可以分成两个点集X和Y,那么任意一条边两个端点分属于不同的点集,也就是说任意一条边的的一个端点在X中,另外一个端点在Y中。并且同一个点集中的任意点之间是没有边相连的,满足这样的性质的图就是二分图。
匹配是指:在给定的一个二分图G中的一个边的子集构成的集合M,M中的任意两条边都没有公共的顶点,那么M就称为一个匹配。那么匹配中含有边数最多的匹配就是最大匹配。
下面来说说匈牙利算法是如何求解二分图的最大匹配的吧。
匈牙利算法是通过不断的找增广路径来扩大匹配集中匹配的边数,我们对左边点集的每一个点找增广路径,直到找不到了增广路径,那么这个时候的匹配就是最大匹配。
匈牙利算法的基本思想就是这样,如果想要具体了解,自己画个图理解下就行了,很容易理解的。下面我们来说说匈牙利算法是如何实现的吧。
首先我们需要构建一个二分图,这个随你。之后为了找增广路径,我们需要一个match[i]表示右边点集的i的匹配的左边的点,如果是-1,那么表示还没有找到匹配的点;这个数组在我们找增广路径的时候非常重要。
其次我们需要一个vis数组,用来表示在每一次找增广路径的时候左边的点是否被访问过,这个是为了防止重复找同一个点而出现错误。
我们再找增广路径的时候,如果一个点的match[i]==-1,那么我们就找到了一条增广路径,返回1;否则我们继续找,对match[i]进行dfs,如果最终都没有找到增广路径,那么就只好返回零表示没有找到增广路径。
基于这个思想,我把在POJ上的2239那道题的代码贴上来,匈牙利算法基本都是差不多的,有需要的可以拿过去参考一下。呵呵——
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LMAX 310
#define RMAX 90
int edge[LMAX][RMAX];
int vis[RMAX],match[RMAX];
int RN;//左边的顶点的个数,右边顶点的个数
int dfs(int i)
{
int j;
for(j=1;j<=RN;j++)
{
if(edge[i][j]&&vis[j]==0)
{
vis[j]=1;
if(match[j]==-1)
{
match[j]=i;
return 1;
}
else
{
if(dfs(match[j]))
{
match[j]=i;
return 1;
}
}
}
}
return 0;
}
int solve(int LN)
{
memset(match,-1,sizeof(match));
int i,sum=0;
for(i=1;i<=LN;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i))
sum++;
}
return sum;
}
int main()
{
int n,t;
int i;
int a,b;
RN=7*12;
// freopen("data.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
memset(edge,0,sizeof(edge));
for(i=1;i<=n;i++)
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&a,&b);
edge[i][(a-1)*12+b]=1;
}
}
printf("%d\n",solve(n));
}
return 0;
}