题意:有n个学生【从0到n-1】,每个学生都可能与其他学生有关系【或者喜欢其他学生】
现在要找出尽量多的人使得这个集合的任意两人都没关系【互相都不喜欢】
思路:相当于都最大点独立集【集合里任意两点都没有边】,
最大点独立集=顶点数-最大匹配数。
注意:而对于这道题来说,我们可以发现这个浪漫关系是相互的。而我们的建图中,按理来说应该是一边是男的点,
一边是女的点这样连边,但是题目中没说性别的问题。只能将每个点拆成两个点,一个当作是男的点,一个当作是女的点了,
然后连边。由于关系是相互的,这样就造成了边的重复。也就是边集是刚才的二倍,从而导致了最大匹配变成了二倍。
/*
Language:C++ (g++ 4.7.2)
Memory:288KB
Time:220MS
*/
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN = 505;
vector<int>map[MAXN];
//邻接矩阵,map[i][j]为1表示Xi喜欢Yj
//用vector可以减少枚举次数,从n降到map[i].size()
int link[MAXN], visy[MAXN];
//link[i]表示最大匹配中与Xi匹配的Y顶点,visy[i]是否访问过
int n;
bool find(int x)
{
for (int i = 0; i < map[x].size(); i++)//枚举与x学生有关系的学生
{
int u = map[x][i];//该学生的编号
if (!visy[u])//没访问过
{
visy[u] = 1;//标记访问
if (link[u] == -1 || find(link[u]))
{//如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到增广路
link[u] = x;
return true;
}
}
}
return false;
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
memset(link, -1, sizeof(link));
int m,k,c,ans=0;
for (int i = 0; i < n; i++)
{
scanf("%d: (%d)", &m, &k);
for (int j = 0; j < k; j++)
{
cin >> c;
map[m].push_back(c);
}
}
for (int i = 0; i < n; i++)
{
memset(visy, 0, sizeof(visy));
if (find(i))//每找到一条增广路,可使得匹配数加1
{
ans++;
}
}
printf("%d\n", (n - ans/2));
//这题的二部图两边集合的点【都是从0到n-1】都一样,所以相当于最大匹配求了两次
for (int i = 0; i < n; i++)//清除map数组信息
{
map[i].clear();
}
}
return 0;
}