标签:
Description:
Input:
Output:
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
题意:有n个学生,问有几个学生一点关系也没有,即两个集合中有多少点它们之间一条连线都没有(最大独立集)
最小顶点覆盖 : 最大匹配数(在二分图中寻找一个尽量小的点集,使图中每一条边至少有一个点在该点集中)
反证法证明:假设当前存在一条两个端点都不在最小顶点覆盖点集中,那么这条边肯定可以增大最大匹配的边集, 与最大匹配矛盾
最小路径覆盖:顶点数-最大匹配数(在二分图中寻找一个尽量小的边集,使图中每一个点都是该边集中某条边的端 点)一条边最多可以包含两个顶点,所以我们选边的时候让这样的边尽量多,也就是说最大匹配的边集数目咯。剩 下的点就只能一个边连上一个点到集合里啦。
最大独立集:顶点数—最大匹配数(除了最大匹配的两个端点,剩下的点肯定是独立的,然后把每个最大匹配的端点取出一个加入独立集,就成了最大独立集) 顶点数-(最大匹配数*2)+最大匹配数 = 顶点数-最大匹配数
#include<stdio.h> #include<string.h> #include<algorithm> #define N 510 using namespace std; int G[N][N], n; int use[N], vis[N]; int Find(int u) //匈牙利算法 { int i; for (i = 0; i < n; i++) { if (!vis[i] && G[u][i]) { vis[i] = 1; if (!use[i] || Find(use[i])) { use[i] = u; return 1; } } } return 0; } int main () { int a, b, m, i, ans, num; while (scanf("%d", &n) != EOF) { memset(G, 0, sizeof(G)); memset(use, 0, sizeof(use)); ans = 0; for (i = 0; i < n; i++) { scanf("%d: (%d)", &a, &m); while (m--) { scanf("%d", &b); G[a][b] = 1; } } for (i = 0; i < n; i++) { memset(vis, 0, sizeof(vis)); if (Find(i)) ans++; } num = n-ans/2; //由于这n个学生中有男生也有女生,那么n就是顶点数,2-3和3-2的关系是一样的,所以最大匹配数需要除以2 printf("%d\n", num); } return 0; }
POJ 1466 Girls and Boys(最大独立集)
标签:
原文地址:http://www.cnblogs.com/syhandll/p/4719092.html