poj2771——Guardian of Decency——————【最大独立集、最大匹配扩展】

/**

   解题思路:将每个学生当做一个结点,如果两个人4个条件都不满足,就意味着他们不能同时被选择,连一条无向边。问题就转化为求这个图的最大独立集。可以分男女入图,也可以不分男女。下面给出两种方法。

*/

题目大意:

               有个思想保守的老师的老师,组织外出,但又怕同学在旅途中产生爱意,于是要求满足带出去的任意两个同学至少满足下面4条中的一条。(1)身高差大于40(2)性别相同(3)喜欢的音乐属于不同类型(4)喜欢的体育比赛相同(他们有可能是不同队伍的球迷,能聊得不愉快)。挑选尽量多的学生,使得任意两个同学满足上述条件中的一条。

——————————————————————

分男女:

/**
    独立集:由一个图两两互不相邻的结点组成。
    最大独立集:选择尽量多的结点,使得任意两个结点不相邻(即任意一条边的两个端点不会同时被选中)。
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXV=550;
bool G[MAXV][MAXV],vis[MAXV];
int match[MAXV];
int n,hei[MAXV];
char sex[MAXV][150],mus_sty[MAXV][150],sport[MAXV][150];
int fabs(int x)
{

    return x>=0?x:-x;
}
bool find_AP(int u){

    for(int i=1; i<=n; i++) {                      //此处i代表女生,u代表男生

        if(strcmp(sex[i],"M"))                     //判断性别,选择女生
            if(G[u][i]&&!vis[i]){

                vis[i]=true;
                if(!match[i]||find_AP(match[i])){

                    match[i]=u;
                    return true;
                }
            }
    }
    return false;
}
int main()
{

    int t;
    scanf("%d",&t);
    while(t--){

        int ans=0;
        scanf("%d",&n);
        memset(G,0,sizeof(G));
        memset(match,0,sizeof(match));
        for(int i=1; i<=n; i++){

            scanf("%d%s%s%s",&hei[i],sex[i],mus_sty[i],sport[i]);
        }
        bool is_sex,is_m_s,is_sp;
        for(int i=1; i<=n; i++){

            for(int j=1; j<=n; j++){

                is_sex=strcmp(sex[i],sex[j]);           //性别是否相同
                is_m_s=strcmp(mus_sty[i],mus_sty[j]);   //喜欢的音乐风格是否相同
                is_sp=strcmp(sport[i],sport[j]);        //喜爱的运动是否相同
                if(fabs(hei[i]-hei[j])<=40&&is_sex&&(!is_m_s)&&is_sp){

                    if(!strcmp(sex[i],"M"))             //过滤掉i为女生的情况
                        G[i][j]=true;                   //建图,性别分离,i代表男性j代表女性
                }
            }
        }
        for(int i=1; i<=n; i++){

            memset(vis,0,sizeof(vis));
            if(!strcmp(sex[i],"M"))                     //由男生开始增广
                if(find_AP(i))
                    ans++;
        }
        printf("%d\n",n-ans);
    }
    return 0;
}
不分男女

——————————————————————

/**
    独立集:由一个图两两互不相邻的结点组成。
    最大独立集:选择尽量多的结点,使得任意两个结点不相邻(即任意一条边的两个端点不会同时被选中)。
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXV=550;
bool G[MAXV][MAXV],vis[MAXV];
int match[MAXV];
int n,hei[MAXV];
char sex[MAXV][150],mus_sty[MAXV][150],sport[MAXV][150];
int fabs(int x)
{

    return x>=0?x:-x;
}
bool find_AP(int u){

    for(int i=1; i<=n; i++) {

            if(G[u][i]&&!vis[i]){

                vis[i]=true;
                if(!match[i]||find_AP(match[i])){

                    match[i]=u;
                    return true;
                }
            }
    }
    return false;
}
int main()
{

    int t;
    scanf("%d",&t);
    while(t--){

        int ans=0;
        scanf("%d",&n);
        memset(G,0,sizeof(G));
        memset(match,0,sizeof(match));
        for(int i=1; i<=n; i++){

            scanf("%d%s%s%s",&hei[i],sex[i],mus_sty[i],sport[i]);
        }
        bool is_sex,is_m_s,is_sp;
        for(int i=1; i<=n; i++){

            for(int j=1; j<=n; j++){

                is_sex=strcmp(sex[i],sex[j]);           //性别是否相同
                is_m_s=strcmp(mus_sty[i],mus_sty[j]);   //喜欢的音乐风格是否相同
                is_sp=strcmp(sport[i],sport[j]);        //喜爱的运动是否相同
                if(fabs(hei[i]-hei[j])<=40&&is_sex&&(!is_m_s)&&is_sp){

                        G[i][j]=true;                   //建图
                        G[j][i]=true;
                }
            }
        }
        for(int i=1; i<=n; i++){

            memset(vis,0,sizeof(vis));
                if(find_AP(i))
                    ans++;
        }
        printf("%d\n",n-ans/2);
    }
    return 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值