C++ and collect classic examples (detailed version of code remarks)

Title description

有一个叫做“数码世界”奇异空间,在数码世界里生活着许许多多的数码宝贝,其中有些数码宝贝之间可能是好朋友,
并且数码宝贝世界有两条不成文的规定:

第一,数码宝贝A和数码宝贝B是好朋友等价于数码宝贝B与数码宝贝A是好朋友

第二,如果数码宝贝A和数码宝贝C是好朋友,而数码宝贝B和数码宝贝C也是好朋友,那么A和B也是好朋友

现在给出这些数码宝贝中所有好朋友的信息,问:可以把这些数码宝贝分成多少组,满足每组中的任意两个
数码宝贝都是好朋友,而且任意两组之间的数码宝贝都不是好朋友

Input format

输入的第一行有两个正整数n(n <= 100)和m(m <= 100),分别表示数码宝贝的个数和好朋友的组数,
其中数码宝贝编号为1~n

接下来有m行,每行两个正整数a和b,表示数码宝贝a和数码宝贝b是好朋友

Output format

输出一个整数,表示这些数码宝贝可以分成的组数

Sample input

7 5
1 2
2 3
3 1
1 4
5 6

Sample output

3

Sample example image

yangli.png

C++ code

#include<iostream>
using namespace std;

const int N = 100;

int a, b, m, n;             //m, n分别为组数和个数  a, b表示每次在同一个集合的两个数
int father[N];              //集

//在合并之前初始化每个节点为该集合的根节点(每个数都是一个集合)
void init(int n) {
    
    
    for (int i = 1; i <= n; i ++ ) father[i] = i;
}

//找到元素x在该集合中的根节点(根节点满足x == father[x])
int findFather(int x) {
    
         //查
    int a = x;  //记录初始节点
    while (x != father[x]) x = father[x];   //循环结束后的x为该集合的根节点
    //路径压缩,将寻找根节点路途中的每个节点指向其根节点,优化之后的查找速度,可不写
    while (a != father[a]) {
    
    
        int b = a;      //记录a,防止后面被覆盖
        a = father[a];  //让a指向其父节点
        father[b] = x;  //指向根节点
    }
    return x;
}

//将a b合并到一个集合中
void Union(int a, int b) {
    
      //并
    //分别找到a, b所在结合的根节点
    int Ra = findFather(a);
    int Rb = findFather(b);
    //当a, b不在同一个集合中时将Ra指向Rb或者将Rb指向Rb指向ba
    if (Ra != Rb) {
    
    
        father[Ra] = Rb;    //将Ra指向Rb
        //father[Rb] = Ra; 也可以
    }
}

int main() {
    
    
    cin >> n >> m;
    init(n);    //在合并集合之前需初始化,勿遗忘
    while (m -- ) {
    
    
        cin >> a >> b;
        Union(a, b);    //每输入两个数,将其合并到一个集合中
    }
    int ans = 0;    //用来记录集合的个数
    //遍历所有数,根节点的数量即为集合的数量
    for (int i = 1; i <= n; i ++ ) {
    
    
        if (i == findFather(i)) ans ++ ;    //i为其所在结合的根节点
    }
    cout << ans << endl;
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_45590494/article/details/105001828
Recommended