题意:为了防止一些学生之间出现couple,老师出游要带的学生要求两两之间满足一些关系中的至少一条才可以带走。求可以带的最多的学生数量。
思路:两个学生之间如果不满足其中的任何一条关系,那么就建边,最后求二分图的最大独立集,也就求出了二分图中的最多的两两之间没有关系的学生(实际是至少满足一条要求的)
#include<iostream>
#include<cmath>
using namespace std;
struct student
{
int h;
char male[5];
char mus[105];
char sport[105];
}stu[510];
bool g[510][510],vis[510];
int link[510];
int N;
bool check(int i,int j)
{
//printf("i=%d j=%d\n",i,j);
//printf("%d\n",abs(stu[i].h-stu[j].h));
//printf("%c %c %s %s %s %s\n",stu[i].male[0],stu[j].male[0],stu[i].mus,stu[j].mus,stu[i].sport,stu[j].sport);
//system("pause");
if(abs(stu[i].h-stu[j].h)<=40&&strcmp(stu[i].male,stu[j].male)!=0&&strcmp(stu[i].mus,stu[j].mus)==0&&strcmp(stu[i].sport,stu[j].sport)!=0)
return true;
return false;
}
bool dfs(int u)
{
for(int i=1;i<=N;i++)
{
if(!vis[i]&&g[u][i])
{
vis[i]=1;
if(link[i]==-1||dfs(link[i]))
{
link[i]=u;
return true;
}
}
}
return false;
}
int maxmatch()
{
int num=0;
memset(link,-1,sizeof(link));
for(int i=1;i<=N;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) num++;
}
return num;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for(int i=1;i<=N;i++)
{
scanf("%d",&stu[i].h);
scanf("%s",stu[i].male);
scanf("%s",stu[i].mus);
scanf("%s",stu[i].sport);
}
//for(int i=1;i<=N;i++)
//{
// printf("%d %s %s %s\n",stu[i].h,stu[i].male,stu[i].mus,stu[i].sport);
//}
//system("pause");
memset(g,0,sizeof(g));
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
{
if(check(i,j))
{
g[i][j]=1;
//printf("标记%d %d\n",i,j);
}
}
//printf("maxmatch=%d\n",maxmatch());
printf("%d\n",N-maxmatch()/2);
}
}