pku(poj) 1466 Girls and Boys (最大独立集)

来源:互联网 发布:照片排版软件哪个好 编辑:程序博客网 时间:2024/05/16 19:40
Girls and Boys
Time Limit: 5000MS                   Memory Limit:10000K
Total Submissions: 7712                   Accepted:3341
Description


In the second year of the university somebody started a study on the romantic relations between the students. The relation "romantically involved" is defined between one girl and one boy. For the study reasons it is necessary to find out the maximum set satisfying the condition: there are no two students in the set who have been "romantically involved". The result of the program is the number of students in such a set.


Input



The input contains several data sets in text format. Each data set represents one set of subjects of the study, with the following description: 


the number of students 
the description of each student, in the following format 
student_identifier:(number_of_romantic_relations) student_identifier1 student_identifier2 student_identifier3 ... 
or 
student_identifier:(0) 


The student_identifier is an integer number between 0 and n-1 (n <=500 ), for n subjects.


Output



For each given data set, the program should write to standard output a line containing the result.


Sample Input



7
0: (3) 4 5 6
1: (2) 4 6
2: (0)
3: (0)
4: (2) 0 1
5: (1) 0
6: (2) 0 1
3
0: (2) 1 2
1: (1) 0
2: (1) 0


Sample Output



5

2


Source


Southeastern Europe 2000


Run IDUserProblemResultMemoryTimeLanguageCode LengthSubmit Time9658080xsxjin1466Accepted228K391MSC++1880B2011-12-13 21:09:07

题目的大意是有n个学生,他们之间有些人存在暧昧关系。你的任务是求出最大的学生个数,这些学生之间满足任意两个学生都没有暧昧关系。

其实这个题目就是用二分图最大匹配求最大独立子集,最大独立集问题: 
在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值. 
如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数 

证明:如果一个有N个点的二分图G的最大匹配数为M,那么未匹配的顶点个数P = N - 2 * M(因为一个匹配连着2个点).

显然这P个点之间没有边连着(不然就不是最大匹配了),又因为在已匹配的点(2*M个)之中,一定至少有M个点和未匹配的P个点之间是没有边连着的,不然就可以找到增广路径(详细证明可以参见最大匹配 = 最小点覆盖),与原题矛盾。

因为题目的输入不能把直接把图存成二分图(x 和 y两部分),所以我写了一个递归MakeBiGraph()函数来标记哪些点属于x部分,哪些点属于y部分。DFS的时候就先判断一下这个点是不是x部分的点。下面是我的代码:




#include <iostream>#include <memory> #include <vector>using namespace std;bool vis[501] , is_x[501];  //is_x数组用来标记顶点是否属于二分图的x部分int stu_num , Match[501];vector<int> BiGraph[501];                //我用的是容器存储图之间关系bool DFS(int x){                          int i , y , size = BiGraph[x].size();for (i = 0; i < size; i++){y = BiGraph[x][i];if (!vis[y]){vis[y] = true;if ( Match[y] == -1 || DFS(Match[y]) ){               //如果找到增广路,去掉偶数边,匹配+1,返回trueMatch[y] = x;return true;}}}return false;   //否则返回false}void MakeBiGraph(int u , bool flag){      //标记与顶点u有关系的顶点,且这些顶点一定与u相反,flag代表u属于哪部分              int v , i , size = BiGraph[u].size();vis[u] = true;for (i = 0; i < size; i++){v = BiGraph[u][i];if (!vis[v]){                                  //如果v还没有访问过,把v标记为与u相反的部分is_x[v] = !flag;MakeBiGraph(v , is_x[v]);                   //  以v去更新和v有关系的顶点,递归}}}int main(){int i , j , stu_id , match_cnt , rela_num;while(scanf("%d" , &stu_num) != EOF){match_cnt = 0;memset(is_x , true , sizeof(is_x));memset(Match , 255 , sizeof(Match));memset(vis , false , sizeof(vis));for (i = 0; i < stu_num; i++){scanf("%d: (%d)" , &j , &rela_num);while(rela_num--){scanf("%d" , &stu_id);BiGraph[j].push_back(stu_id);}}for (i = 0; i < stu_num; i++){if (!vis[i]){MakeBiGraph(i , is_x[i]);     //从顶点0 至 stu_num - 1标记与它们有关系的顶点}}for (i = 0; i < stu_num; i++){if (is_x[i]){              //如果属于x部分,DFS找增广路memset(vis , false , sizeof(vis));if (DFS(i) == true){            //如果找到增广路,匹配数+1 match_cnt++;}}}printf("%d\n" , stu_num - match_cnt);        //输入最大独立子集个数for (i = 0; i < stu_num; i++){BiGraph[i].clear();}}return 0;}


原创粉丝点击