/** 题目:Guardian of Decency UVALive - 3415 最大独立集=结点数-最大匹配数 老师带大学生旅游 链接:https://vjudge.net/problem/UVALive-3415 题意:老师带学生去旅游,要求从n个学生中选出一些学生,满足任意两个学生至少要满足下面的四条中的一条。 1,身高相差大于40cm 2,性别相同 3,最喜欢的音乐不同类型 4,最喜欢的体育比赛相同类型 输出可以挑选的最多学生人数。 思路:最大独立集做法。 选出来的学生必须满足上面四个条件至少一个。 那么如果两个学生都不满足上面的条件,则最多只能从中选一个人。 所以:如果学生a和学生b不满足上面的条件,那么连一条边,题目要求选的学生中,任意两个学生不能有边相连。 这就是最大独立集(选择尽量多的结点,使得任意一条边的两个端点不会同时被选中)问题。 处理:左边编号为1~n的学生,右边也是编号1~n的学生,相同编号的学生不连边,如果学生a和学生b不满足上面的条件,那么连一条边。 由于令x为左边的学生编号,y为右边的学生编号(x!=y) 如果x与y连边,那么y与x也会连一条边,所以边数多了一倍。 那么最大匹配数也会多一倍。 本题结果:ans = N-最大匹配数/2: 最大独立集=结点数-最大匹配数。 */ #include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<vector> #include<queue> #include<set> #include<cstring> using namespace std; const int MAXN = 505; int f[MAXN][MAXN]; int vit[MAXN], S[MAXN], T[MAXN]; int N; ///模板 bool Find(int x)///走交替路,寻找增广路 { for(int i = 1; i <= N; i++){///n表示右侧点数。 if(f[x][i]&&vit[i]==0){ vit[i] = 1; if(T[i]==0||Find(T[i])){ T[i] = x;///右边第i个点和左边第x个点匹配成功。 S[x] = i;///左边第x个点和右边第i个点匹配成功。 return true; } } } return false; } struct node { int h; char sex[2]; char music[102]; char sport[102]; }stu[MAXN]; int main() { int n, m, k; cin>>k; while(k--){ scanf("%d",&n); N = n; memset(f, 0, sizeof f); for(int i = 1; i <= n; i++){ scanf("%d%s%s%s",&stu[i].h,stu[i].sex,stu[i].music,stu[i].sport); } for(int i = 1; i <= n; i++){///每条边都重复了一次。对称。最终匹配数要对半; for(int j = 1; j <= n; j++){ if(i==j) continue; if(abs(stu[i].h-stu[j].h)<=40&&stu[i].sex[0]!=stu[j].sex[0]&&strcmp(stu[i].music,stu[j].music)==0&&strcmp(stu[i].sport,stu[j].sport)!=0){//都不满足 f[i][j] = 1; } } } int ans = 0; memset(T, 0, sizeof T); memset(S, 0, sizeof S); ///模板 for(int i = 1; i <= N; i++){ memset(vit, 0, sizeof vit); if(Find(i)) ans++; } printf("%d",N-ans/2); printf(" "); } return 0; }