团伙(Group)

120 阅读2分钟

线上OJ:

1385:团伙(group)

核心思想:

1、朋友的朋友就是朋友。这句话意味着朋友之间直接合并

2、敌人的敌人就是朋友。这句话说明,如果 a 和 b 是敌人,a 和 c 也是敌人,则 c 和 b 就是朋友。如果 a 和 d 也是敌人,则 d 和 {c, b} 都是朋友。

2.1 所以当 a 和 x 是敌人时,xa 的敌人 合并即可。用一个数组 a[i] 记录第 i 个人的敌人(只需记录一个即可,因为合并时会合并他们的根节点)。

2.2 如果 a 和 x 是敌人,但 a[i] 数组为空,则把 x 赋值给 a[i],作为它的第一个敌人。

3、最后判断有几个团伙时,只要数下有几个根即可(p[i]==i 的为根)。

题解代码:

#include <bits/stdc++.h>

using namespace std;

int p[1010], enemy[1010] = {0}, n, m, x, y, k;

int find(int x)  // 查询x所在集合中的根节点
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void unionn(int x, int y)  // 合并x和y
{
    int a = find(x), b = find(y);
    if (a != b) p[a] = b;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )  p[i] = i;  // 初始化每个元素的根节点为自己
    for (int i = 1; i <= m; i ++ )
    {
        scanf("%d%d%d", &k, &x, &y);
        if (k == 0)
            unionn(x, y);  // 如果两个人是朋友,直接合并
        else if (k == 1)
        {
            if(!enemy[x])
                enemy[x] = y;  // 如果x还没有敌人,则赋值y为x的敌人
            else
                unionn(enemy[x], y);  // 如果x已经有敌人,则把y合并到x的敌人群里(敌人的敌人就是朋友)

            if(!enemy[y])  // 反之亦然
                enemy[y] = x;
            else
                unionn(enemy[y], x);
        }
    }

    int ans = 0;
    for(int i = 1; i <= n; i++)
        if(p[i] == i)  ans++;   // 满足p[i] == i的说明是根。根的数量就要是团伙的数量

    printf("%d\n", ans);
}