POJ 3692 最小点覆盖 最大二分图匹配

题目在这里:http://poj.org/problem?id=3692

大意是说,在幼儿园中有N女孩M个男孩,其中所有的女孩互相认识,所有的男孩互相认识,并且有一些男孩和女孩互相认识。现在要你找出最多的人,他们都互相认识。

这个题目最开始看起来的时候没有想清楚如何转换成最大二分图,在网上找了一些人的文章,一些思路是在二分图里找到最大子团,然后转换成二分图。


想了好久,我觉得这样理解是比较好的。

因为在所有男孩和女孩之间,题目都互相认识,如果图是基于“认识", 那么图将如图所示。其实这个图根本不满足二分图的蒂定义,因为左侧点和右侧点互相是存在连接的,而在二分图的定义中,这样的连接是不存在的。



如果我们找到这样几个同学,将他们去除整个集合之后,所有的”不认识“都可以消除,那么剩余的同学之间不就都全认识了吗?! 所以我们根据”不认识关系“建立图如下,可以看出这正好符合二分图的定义。然后我们将二分图中找出一些点,这些点可以覆盖所有的”不认识"关系。这里我们就把问题转换为“最小覆盖问题”。



根据定理,我们知道,最小覆盖数 == 最大匹配数,所以编程找到最大匹配数目即可。

程序如下:

#include <stdio.h>
#include <memory.h>
#define MAX_BOY_GIRL 202

int Relation[MAX_BOY_GIRL][MAX_BOY_GIRL];
int visit[MAX_BOY_GIRL];
int matched[MAX_BOY_GIRL];

int nGirl;
int nBoy;
int nRelation;

bool dfs(int iGirl)
{
	for( int i = 1; i <= nBoy; i++)
	{
		if(Relation[iGirl][i] == 0 && !visit[i])
		{
			visit[i] = true;
			if(matched[i] == -1 || dfs(matched[i]))
			{
				matched[i] = iGirl;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int icase = 1;
	while(scanf("%d%d%d", &nGirl, &nBoy, &nRelation))
	{
		if(nGirl == 0 && nBoy == 0 && nRelation == 0)
		{
			break;
		}

		memset(Relation, 0, sizeof(Relation));
		memset(matched, -1, sizeof(matched));
		int f,t;
		for( int i = 0; i < nRelation; i++)
		{
			scanf("%d%d", &f, &t );
			Relation[f][t] = 1;
		}

		int count = 0;
		for( int i = 1; i <= nGirl; i++)
		{
			memset(visit, 0, sizeof(visit));
			if(dfs(i))
			{
				count++;
			}
		}
		printf("Case %d: %d\n",icase, nGirl + nBoy - count);
		icase++;

	}
	return 0;
	
}



你可能感兴趣的:(POJ 3692 最小点覆盖 最大二分图匹配)