Guardian of Decency UVALive - 3415 最大独立集=结点数-最大匹配数 老师带大学生旅游

/**
题目: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("\n");
    }
    return  0;
}

 

posted on 2017-07-20 13:31  hnust_accqx  阅读(175)  评论(0编辑  收藏  举报

导航