如果四个条件都满足的话,就把两个学生连边,代表这两个学生不能共存
最后肯定是一个二分图,因为一个学生不是男生就是女生,然而男生和女生两部内部是没有连边的
所以问题变成了删去最小的点,使所有边最多只有一个点
还是二分图最小覆盖(和最大独立集互补),不需要求方案,跑一遍就可以了
#include<cstdio>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<iostream>
#define fr(i,s,t) for (i=s;i<=t;i++)
using namespace std;
int n,match[1001];
bool vy[1001];
struct student{
int hei;
char male;
string music,sport;
}q[600];
vector <int> vec[501];
bool hungary(int x){
int i,y;
for (i=0;i<vec[x].size();i++){
y=vec[x][i];
if (vy[y]) continue;
vy[y]=1;
if (!match[y]||hungary(match[y])){
match[y]=x;
return 1;
}
}
return 0;
}
void work(){
scanf("%d",&n);
int i,j,ans=0;
fr(i,1,n) vec[i].clear();
memset(match,0,sizeof(match));
fr(i,1,n)
cin>>q[i].hei>>q[i].male>>q[i].music>>q[i].sport;
fr(i,1,n) fr(j,i+1,n)
if (abs(q[i].hei-q[j].hei)<=40&&q[i].male!=q[j].male&&q[i].music==q[j].music&&q[i].sport!=q[j].sport){
vec[j].push_back(i);
vec[i].push_back(j);
}
fr(i,1,n)
if (q[i].male=='M')//也可以不区分男生女生,但最后结果要/2
{
memset(vy,0,sizeof(vy));
if (hungary(i)) ans++;
}
cout<<n-ans<<endl;
}
int main(){
int n1;
scanf("%d",&n1);
while (n1--) work();
return 0;
}