题目在这里: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; }