题意:有N个学生,现要从中选出尽量多的学生,使得选出来的学生中任意两个学生满足至少满足下列4个条件中的1个:
1.身高相差超过40
2.同性
3.喜欢的音乐类型不同
4.喜欢的运动类型相同
问最多能选出多少个学生(测试组数T <= 100, N <= 500, 音乐类型和运动类型的字符串长度不超过100)。
——>>反向思考,怎样的学生不能一起选呢?以上4个条件一个都不满足的学生不能一起选。以男生为X结点,女生为Y结点,不能一起选的学生之间连一条边建立二分图,那么原题就转化为在这个二分图中找出尽量多的点使得选出的点中任意两点之间没有边相连,这正正是二分图的最大独立点集。
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxw = 100 + 10;
const int maxn = 500 + 10;
const int maxm = 62500 + 10;
int N, h[maxn], boy[maxn], girl[maxn], b, g, head[maxn], nxt[maxm], v[maxm], ecnt, fa[maxn];
bool S[maxn], T[maxn];
char music[maxn][maxw];
char sport[maxn][maxw];
void init(){
memset(head, -1, sizeof(head));
ecnt = 0;
}
void addEdge(int uu, int vv){
v[ecnt] = vv;
nxt[ecnt] = head[uu];
head[uu] = ecnt;
ecnt++;
}
void read(){
char sex;
b = 1, g = 1;
scanf("%d", &N);
for(int i = 1; i <= N; i++){
scanf("%d %c%s%s", &h[i], &sex, music[i], sport[i]);
if(sex == 'M') boy[b++] = i;
else girl[g++] = i;
}
}
void love(){
init();
for(int i = 1; i < b; i++)
for(int j = 1; j < g; j++)
if(abs(h[boy[i]] - h[girl[j]]) <= 40 && !strcmp(music[boy[i]], music[girl[j]]) && strcmp(sport[boy[i]], sport[girl[j]]))
addEdge(i, j);
}
bool match(int i){
S[i] = 1;
for(int e = head[i]; e != -1; e = nxt[e]) if(!T[v[e]]){
T[v[e]] = 1;
if(!fa[v[e]] || match(fa[v[e]])){
fa[v[e]] = i;
return 1;
}
}
return 0;
}
void solve(){
int Max = 0;
memset(fa, 0, sizeof(fa));
for(int i = 1; i < b; i++){
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
if(match(i)) Max++;
}
printf("%d\n", N - Max);
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
read();
love();
solve();
}
return 0;
}