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

来源:互联网 发布:软件系统开发合同 编辑:程序博客网 时间:2024/05/22 03:03

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

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

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


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

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



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



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

程序如下:

#include <stdio.h>#include <memory.h>#define MAX_BOY_GIRL 202int 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;}