【二分图】2021年度训练联盟热身训练赛第五场 F: Group Project

Group Project

传送门
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目大意:
现有两个班级, 1 1 1 班和 2 2 2 班;两个班一共有 n n n 名同学,现在要将这 n n n 名同学分成若干个小组,每个小组由 2 2 2 名同学组成。
小组内的两个同学若来自同一班级,则一定不会产生矛盾;
若来自不同的班级,则可能会产生矛盾。
给出 m m m 对关系,每对关系表示这两名同学若分在一个小组会发生矛盾。
求最多能够划分出多少个小组,且每个小组内都不会产生矛盾。
解题思路:
因为同一班级的同学构成小组不会发生任何矛盾,所以应先在班级内部划分小组。若 1 1 1 班有 x x x 个同学, 2 2 2 班有 y y y 个同学, 则在 1 1 1 班一定可以划分出 ⌊ x 2 ⌋ \lfloor{\frac{x}{2}}\rfloor 2x 个不产生矛盾的小组,在 2 2 2 班也一定可以划分出 ⌊ y 2 ⌋ \lfloor{\frac{y}{2}}\rfloor 2y 个不产生矛盾的小组。若 x x x y y y 都是奇数,则会产生一个由来自不同班级的两个学生组成的小组,这种情况只需查找在两个班级中是否存在一对不产生矛盾的同学即可。简单的判断就是 x × y x×y x×y m m m 的关系, 若 x × y x×y x×y m m m 相等, 则说明:分别从1班和2班各抽取 1 位同学组成的小组一定会产生矛盾;否则,则说明可以构成一个小组。

好了,上述分析之后基本思路应该就清楚了,问题转化为求两个班级各有多少人即可。也就是求上述中的 x x x y y y 分别是多少。
x x x y y y 的分析:
为便于表达,此处将用 n n n 个点来表示 n n n 位同学。因有且仅有两个班级,则可以将 n n n 个点划分为两个部分。因给出的 m m m 对关系中,两个点是来自不同部分的,我们考虑用二分图染色法来解决,若两个点之间存在矛盾,则将其标记为不同的颜色。将所有的点染色之后,即可求得 x x x y y y 的值。

上代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 400010;
int h[N],e[N],ne[N],idx;
int color[N];
void add(int a,int b)
{
    e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}
void dfs(int u,int c)
{
    if(color[u]) return;
    color[u] = c;
    for(int i = h[u];i != -1;i = ne[i])
    {
        int j = e[i];
        dfs(j,3 - c);
    }
}
int main()
{
    int n,m; scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    for(int i = 1;i <= m;i++)
    {
        int x,y; scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    dfs(1,1);
    int x = 0,y = 0;
    for(int i = 1;i <= n;i++)
    {
        //cout << color[i] << " ";
        if(color[i] == 1) x++;
        else y++;
    }
    int res = x/2 + y/2;
    if((x & 1) && (y & 1) && (x * y != m)) res++;
    cout << res;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值