九度 1526:朋友圈(并查集)

题目描述:

假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。
假如:n = 5 , m = 3 , r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。

 

思路

1. 裸的并查集, 回顾下并查集的知识

2. 并查集主要有两个操作, 一个是 merge, 一个是 find. find 用于找到一个集合的标志, merge 用于合并两个集合. 在实际的操作中, 我们只要用 merge 就好了, find 不直接使用

3. find 又有路径压缩的说法, 这是在寻找集合标志的过程中, 使得这条路径上的所有节点到标志的距离都压缩成 1, 使用递归完成

4. 比较来了两个节点 0 1, 我们要做的就是 merge(0,1), 将 0, 1 合并到一个集合中. merge 的实际操作是将两个集合的标志建立父子关系

 

代码

 

#include <iostream>
#include <stdio.h>
using namespace std;

int father[100010];

int find(int x) {
    if(father[x] != x) {
        father[x] = find(father[x]);
    }
    return father[x];
}

void merge(int a, int b) {
    int fa = find(a);
    int fb = find(b);
    if(fa == fb)
        return;
    father[fa] = fb;
}

int main() {
    //freopen("testcase.txt", "r", stdin);
    int n, m;
    while(scanf("%d", &n) && n != 0) {
        scanf("%d", &m);
        for(int i = 1; i <= n; i ++)
            father[i] = i;

        int a, b;
        for(int i = 0; i < m; i ++) {
            scanf("%d%d", &a, &b);
            merge(a,b);
        }
        int cnt = 0;
        for(int i = 1; i <= n; i ++) {
            if(father[i] == i)
                cnt++;
        }
        cout << cnt << endl;
    }
    return 0;
}

 

posted @ 2014-03-04 20:16  SangS  阅读(769)  评论(0编辑  收藏  举报