二分图的最大匹配问题

二分图的题有很多不同种的问法,这里先总结一下二分图的最大匹配问题;

求二分图的最大匹配问题我们通常使用的是匈牙利算法;

要理解匈牙利算法的核心思想,就要先弄懂一个概念 —— 增广路

增广路的几个要求:

有奇数条边。

起点在二分图的左半边,终点在右半边。

路径上的点一定是一个在左半边,一个在右半边,交替出现。(其实二分图的性质就决定了这一点,因为二分图同一边的点之间没有边相连,不要忘记哦。)

整条路径上没有重复的点。

起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。

路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。

  7 最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个。

然后给出hdu2063的代码,理解了匈牙利算法的核心要理解程序并不是很难。
/* hdu 2063 过山车*/
#include 
#include 
#include 
#include 
using namespace std;

int map[520][520],match[520],vis[520];
int n,m;
int zgfind(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(map[x][i]==1 && vis[i] == 0)				//找到存在边并且未被搜索过的点
		{
			vis[i]=1;								//标记节点已经被访问避免重复判断
			if( match[i]==0 || zgfind(match[i])==1)	//如果i是一个未匹配点或者i点相匹配的点能找到其它匹配点
			{
				match[i]=x;							//生成新的匹配
				return 1;		
			}
		}
	}
	return 0;
}
int main()
{
	int k,a,b;
	while(scanf("%d",&k)!=EOF&&k)
	{
		int ans = 0;
		memset(map,0,sizeof map);
		memset(match,0,sizeof match);
		memset(vis,0,sizeof vis);
		scanf("%d%d",&n,&m);
		while(k--)
		{
			scanf("%d%d",&a,&b);
			map[a][b]=1;
		}
		for(int i=1;i<=n;i++)
		{
			memset(vis,0,sizeof vis);			//在每次dfs增广路时避免重复访问节点;
			if(zgfind(i))
				ans++;
		}
		cout<
 在查找增广路的函数里实现了二分图左边的点和右边的点的匹配,如果右边的点是一个未被匹配的点,那么左边的点就可以直接与之相匹配,如果右边的点是一个已经被匹配的点,那么查找他的匹配点能否找到一个未被匹配的点作为新的匹配;



你可能感兴趣的:(二分图的最大匹配问题)