打开题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2458
本题其实就是在求最大独立子图(最大完全数)(注意在这个算法里没有将最大独立子图所包含的元素求出来)(也就是说现在最大独立子图还不会求... )
解题思路:
本题应该是在匈牙利算法上的一个小的变式,这道题的难点在于转化,题目要求的是一个集合,集合中的任意两个顶点之间都有连线,求出全部都联通的最大数,但是二部图中并没有专门相关的方法解决这个问题.
然而,通过合理的转化,这个问题也就变成了二部图范畴内的问题:
一般的建图方式是u和v认识,就在u和v之间连一条边,但是这道题要反过来做,彼此不认识就连一条边,这么一来求出二部图的最大独立集就是答案,因为独立集内部所有顶点之间没有连线,也就是互相认识,而且是这个独立集是最大的.
下面补充几个(下面的这几个概念对本体来说很重要,关于二分图的概念参考网址)
二分图又称作二部图
独立集:任意两点都不相连的顶点的集合
独立数:独立集中顶点的个数//完全子图:任意两点都相连的顶点的集合
完全子图:任意两点都相连的顶点的集合
最大完全数:最大完全子图中顶点的个数
最大完全数=原图的补图的最大独立数
最大独立数=总的顶点数-最大匹配数(这里不是)
本题是要求图中的最大完全子图(最大团)中顶点的个数。
由于原图的补图是一个二分图,其最大完全数等价于其补图的最大独立集中元素的个数,
于是可以根据二分图的性质求出这个最大独立集。而普通图的最大团则是一个NP问题。
定理:二分图最大独立集=顶点数-二分图最大匹配(匈牙利算法)
最大完全数:图中最大完全子图的顶点个数。
独立集:图中任意两个顶点都不相连的顶点集合。
以上这几个概念有点乱,但是得好好想想。。。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 1000; int girl, boy ; // u, v数目,要初始化!!! bool g[MAXN][MAXN]; // g[i][j] 表示xi与yj相连 int match[MAXN]; // 记录男生是否匹配以及匹配情况 bool check[MAXN]; // 辅助量检查某轮match[i]是否被check bool SearchPath(int u){ //匈牙利算法 int v; for(v = 0; v < boy; v++) if( g[u][v] && !check[v]) { check[v] = true; if( match[v] == -1 || SearchPath( match[v] )) { match[v] = u; return true ; } } return false ; } int main() { int m,i,a,b,cnt=0,j; while ( scanf("%d%d%d", &girl, &boy, &m) && (girl||boy||m) ) { cnt++; //计数 memset(g,1,sizeof(g)); while(m--) //标记 { scanf("%d%d",&a,&b); g[a-1][b-1]=false; //认识的人没有边 } int u, count = 0 ; memset( match, -1, sizeof(match) ); for( u = 0; u < girl; u++ ) { memset(check, 0, sizeof (check)); if(SearchPath(u)) count++; } printf("Case %d: ",cnt); printf("%d\n",girl+boy-count); } }
有木有感觉和匈牙利算法很像。。。