LA-3415 & POJ-2771 Guardian of Decency 解题报告

       二分图求最大独立集。题意:Frank是一个思想保守的老师。有一次他需要带一些学生出去旅行,但是又怕其中一些学生在旅途中萌生爱意。为了降低这种事情的发生概率,他决定确保带出去的任意两个学生至少要满足下面4个条件中的一条:

1.身高相差要大于40厘米

2.性别相同

3.最喜欢的音乐类型不同

4.最喜欢的体育比赛相同(因为他们很可能是不同的球队的球迷,这样他们就可能聊得很不愉快)

现在的任务是帮助Frank挑选尽量多的学生,使得任意两个学生至少满足上述条件中的一条。


       我的解题思路:因为人的性别只有男女两种,所以这里就有两种不同的点集,为二分图的构建奠定了基础,因为性别相同的两个人是不可能互相产生爱意的(不要跟我讨论同性恋问题-_-||)。题意是如果两个学生之间满足上述4个条件中的一个,那么这两个学生是不可能产生爱意的。那么两个学生产生爱意的唯一可能是上述四个条件都不满足,如果两个学生能够产生爱意,那么可以给这两个学生连一条无向边。这样,二分图就构建完毕,最后题目要求确保带出去的学生任意两个都不能产生爱意,即任意两个学生之间都没有连一条边,而且要求带出去的学生尽量多,这正是二分图求最大独立集的性质。根据二分图最大独立集等于二分图点数减去最大匹配数可得答案。


       我的解题代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

#define N 505
#define M 101

struct student  //定义学生信息结构体
{
    int height;     //身高
    bool man;       //是否为男性
    char music[M];  //最喜欢的音乐类型
    char sport[M];  //最喜欢的体育比赛的类型
};

int match[N];
bool vis[N];
vector <int> e[N];
student node[N];    //存储每个学生的信息
int t, n;

void InitRead();

void DataProcess();

bool Dfs(int x);

int main()
{
    scanf("%d", &t);
    while (t--)
    {
        InitRead();
        DataProcess();
    }
    return 0;
}

void InitRead()
{
    memset(match, -1, sizeof(match));
    char sex;
    scanf("%d", &n);
    for (int i=0; i<n; ++i)     //输入学生信息顺便初始化邻接表
    {
        e[i].clear();
        scanf("%d", &node[i].height);
        scanf(" %c", &sex);
        node[i].man = sex == 'M' ? true : false;
        scanf("%s %s", node[i].music, node[i].sport);
    }
    for (int i=0; i<n; ++i) //开始准备建边
    {
        for (int j=i+1; j<n; ++j)
        {
            if (node[i].man == node[j].man) continue;
            if (abs(node[i].height - node[j].height) > 40) continue;
            if (strcmp(node[i].music, node[j].music) != 0) continue;
            if (strcmp(node[i].sport, node[j].sport) == 0) continue;
            //到达这里说明四个条件都没有满足,可能萌生爱意,接下来建无向边
            e[i].push_back(j);
            e[j].push_back(i);
        }
    }
    return;
}

void DataProcess()
{
    int ans = 0;
    for (int i=0; i<n; ++i)
    {
        memset(vis, false, sizeof(vis));
        if (Dfs(i)) ans++;
    }
    printf("%d\n", n - ans / 2);
    return;
}

bool Dfs(int x)
{
    int size = e[x].size();
    for (int i=0; i<size; ++i)
    {
        if (!vis[e[x][i]])
        {
            vis[e[x][i]] = true;
            if (match[e[x][i]] == -1 || Dfs(match[e[x][i]]))
            {
                match[e[x][i]] = x;
                return true;
            }
        }
    }
    return false;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值