版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mobius_strip/article/details/87545303
题目
有N个人要参加宴会,他们之间有些人有敌对关系,敌对关系是对称的,而且可以传递(敌人的敌人是朋友)。求最多可以邀请多少人。
分析
图论,二分图匹配。将人们的关系分成四种:0没有关系,-1敌对关系,1朋友关系(敌人的敌人是朋友-1*-1 = 1),2矛盾关系(即使朋友又是敌人,如第三组数据);可以利用乘法来传递关系。将矛盾的人全部删除(通过传递可以得到他们是自己的敌人),然后求最小覆盖(等于最大匹配),N - 最小覆盖即使结果。
说明
ε=(´ο`*)))唉。。。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int relation[202][202];
int used[202], link[202];
// Bipartite graph matching
int dfs(int s, int n)
{
for (int i = 1 ; i <= n; ++ i) {
if (relation[s][i] == -1 && !used[i]) {
used[i] = 1;
if (link[i] == -1 || dfs(link[i], n)) {
link[i] = s;
link[s] = i;
return 1;
}
}
}
return 0;
}
int main()
{
int M, N, p, enemy;
while (~scanf("%d", &M))
while (M --) {
scanf("%d", &N);
for (int i = 1; i <= N; ++ i) {
for (int j = 1; j <= N; ++ j) {
relation[i][j] = 0;
}
link[i] = -1;
}
for (int i = 1; i <= N; ++ i) {
scanf("%d", &p);
for (int j = 1; j <= p; ++ j) {
scanf("%d", &enemy);
relation[i][enemy] = -1;
relation[enemy][i] = -1;
}
}
// Delete the contradiction nodes
for (int k = 1; k <= N; ++ k) {
for (int i = 1; i <= N; ++ i) {
for (int j = 1; j <= N; ++ j) {
int new_relation = relation[i][k] * relation[k][j];
if (new_relation) {
if (relation[i][j] == 0) {
relation[i][j] = relation[i][k] * relation[k][j];
}else if (relation[i][j] != new_relation ||
new_relation == 2 || new_relation == -2) {
relation[i][j] = 2;
link[i] = -2;
}
}
}
}
}
int sum = 0;
for(int i = 1 ; i <= N ; ++ i) {
if (link[i] == -2) sum += 1;
if (link[i] != -1) continue;
for (int j = 1; j <= N; ++ j) {
used[j] = 0;
}
sum += dfs(i, N);
}
printf("%d\n", N - sum);
}
return 0;
}