NSUOJ3161朋友(并查集)

该博客介绍了如何利用并查集数据结构解决一个关于社交网络中朋友关系和敌对关系的问题。给定一定数量的人、朋友对和敌对对,目标是找出每个人有多少个潜在的朋友(朋友的朋友但不是敌人)。博客中提供了详细的解题思路,即先通过并查集计算每个人的朋友总数,然后减去候选朋友和敌对朋友的数量,得到最终的候选朋友数。最后,给出了C++代码实现来解决这个问题。
摘要由CSDN通过智能技术生成

一、题目描述

Description
有N个人编号从1 ~ N,M对朋友关系和K对敌对关系。
现在给每个人找候选朋友,候选朋友是他的间接朋友(朋友的朋友),但不能与他是敌对关系。
问每个人有多少个候选朋友。
Input
第一行为三个整数N,M,K。
后面M行,每行两个整数Ai,Bi,表示朋友关系。
接下来K行,每行两个整数Ci,Di,表示敌对关系。
2 ≤ N ≤ 105
0 ≤ M , K ≤ 105
1 ≤ Ai , Bi ≤ N
1 ≤ Ci , Di ≤ N
Ai ≠ Bi , Ci ≠ Di
(Ai , Bi) ≠ (Aj , Bj) (i ≠ j)
(Ai , Bi) ≠ (Bj , Aj)
(Ci , Di) ≠ (Cj , Dj) (i ≠ j)
(Ci , Di) ≠ (Dj , Cj)
(Ai , Bi) ≠ (Cj , Dj)
(Ai , Bi) ≠ (Dj , Cj)

Output
从编号1 ~ N,依次输出他有多少个候选朋友,中间留空格。
Sample Input Copy
4 4 1
2 1
1 3
3 2
3 4
4 1
Sample Output Copy
0 1 0 1

二、解题思路

我们可以直接使用并查集获得每个朋友的朋友总数(朋友总数等于父节点的子节点个数),然后将朋友总数减去候选朋友和敌对朋友的和即可(注意:如果敌对的朋友不属于同一个朋友圈中就没有必要记录这个数了,他们都不在一个朋友圈中,自然也不可能是朋友)。我们使用两个数组,一个数组记录当前该人的总朋友的个数,一个数组记录当前该人的候选朋友的数量加敌对朋友的数量,最后遍历相减,可AC。

三、代码实现

#include <iostream>
using namespace std;
int pre[200010];
int n, m, k, a, b;
int ct1[200010], ct2[200010];
int find(int x) {
    return pre[x] == x ? x : pre[x] = find(pre[x]);
}
void join(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx != fy) {
        pre[fy] = fx;
        ct1[fx] += ct1[fy];//记录朋友圈里的总人数
    }
}
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++) {
        pre[i] = i; ct1[i] = 1;
    }
    for (int i = 0; i < m; i++) {
        scanf("%d%d", &a, &b);
        join(a, b);
        ct2[a]++; ct2[b]++;//记录候选朋友个数
    }
    for (int i = 0; i < k; i++) {
        scanf("%d%d", &a, &b);
        int kk = find(a), s = find(b);
        if (kk == s) {//两人是否在同一个圈子中,是就必须记录该敌对数
            ct2[a]++;
            ct2[b]++;
        }
    }
    for (int i = 1; i <= n; i++) {//遍历相减
        if (i == n) printf("%d\n", ct1[find(i)] - ct2[i] - 1);//减一代表减去自己
        else printf("%d ", ct1[find(i)] - ct2[i] - 1);
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值