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

Group Project

传送门
【二分图】2021年度训练联盟热身训练赛第五场 F: Group Project_第1张图片
【二分图】2021年度训练联盟热身训练赛第五场 F: Group Project_第2张图片
【二分图】2021年度训练联盟热身训练赛第五场 F: Group Project_第3张图片
题目大意:
现有两个班级, 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
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;
}

你可能感兴趣的:(图论)