## [$POJ$ $1466$ $Girls$ $and$ $Boys$](http://poj.org/problem?id=1466) ### 一、题目描述 大意就是有$n$个人,每个人与其他的某几个人有关系,这个关系且称为 **浪漫关系**,然后最后求一个最大的集合,使得 **集合中所有的人两两之间都不存在浪漫关系**。 ### 二、题目分析 看到之后就可以发现,这是一道非常明显的 **最大独立集** 的问题,可以转化为二分图来做,还是最经典的拆点建图,然后根据定理,**最大独立集=顶点数-最小点覆盖数**。 而对于这道题来说,我们可以发现这个浪漫关系是相互的。 而我们的建图中,按理来说应该是一边是男的点,一边是女的点这样连边,但是题目中没说性别的问题。 只能将每个点拆成两个点,一个当作是男的点,一个当作是女的点了,然后连边。由于关系是相互的,这样就造成了边的重复。也就是边集是刚才的二倍,从而导致了最大匹配变成了二倍。 那么 ,最大独立集=顶点数-最大匹配$/2$,所以最终答案就呼之欲出了。 ### $Code$ ```cpp {.line-numbers} #include #include #include #include #include #include #include #include using namespace std; const int N = 510, M = N * N; // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } // 匈牙利算法模板 int match[N], st[N]; int dfs(int u) { for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (st[v]) continue; st[v] = 1; if (match[v] == -1 || dfs(match[v])) { match[v] = u; return 1; } } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("POJ1466.in", "r", stdin); #endif int n; while (~scanf("%d", &n)) { memset(h, -1, sizeof h); idx = 0; for (int i = 0; i < n; i++) { int m, a, b; scanf("%d: (%d)", &a, &m); while (m--) { scanf("%d", &b); add(a, b); } } int res = 0; memset(match, -1, sizeof match); for (int i = 0; i < n; i++) { memset(st, 0, sizeof st); if (dfs(i)) res++; } printf("%d\n", n - res / 2); } return 0; } ```