并查集

并查集练习

题目要求

有N个节点,初始状态互相独立,没有边相连,读入N后,每一行的指令结构为

I 数字1 数字2 // 连接节点1和2
C 数字1 数字2 // 检查节点1和节点2之间有没有路径,若有输出yes,反之输出no
S // 检查网络一共有几片联通片,结束程序

输入样例1:

5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S

输出样例1:

no
no
yes
There are 2 components.

输入样例2:

5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S

输出样例2:

no
no
yes
yes
The network is connected.

分析

  1. 使用一个长度为N的数组存放节点,数组的下标代表节点编号-1,数组的元素有正负两种。若为正,代表这个节点的夫节点的编号-1,若为负,则为根节点,绝对值表示以这个节点为根的树的元素数量。初始状态所有节点置为-1.
  2. 每次连接两个节点时,将这两个节点所在树的根节点相连(默认输入的两个节点为不同树的节点),因为根节点一旦相连,则这两棵树合二为一,这两个节点自然相连了。要注意这里使用“按秩归并”算法,每次连接始终把节点数量较小的树根指向节点数量较多的树根。
  3. 查找某个节点的树根时,使用“压缩路径”算法,即每次查找都把当前节点指向树根。

C原码

#include <stdio.h>
#include <stdlib.h>

typedef int SetType;

int FindRoot(SetType S[], int x);
void Union(SetType S[], int x, int y);
void Initial(SetType S[], int sum);
void Check(SetType S[]);
void Connect(SetType S[]);
void Output_Network(SetType S[], int sum);

int main()
{
    int sum;
    char in;
    scanf("%d\n", &sum);
    SetType S[sum];
    Initial(S, sum);
    do
    {
        scanf("%c ", &in);
        switch(in)
        {
            case 'I' : Connect(S);
                break;
            case 'C' : Check(S);
                break;
            case 'S' : Output_Network(S, sum);
                break;
        }
    }while(in != 'S');

    return 0;
}

void Initial(SetType S[], int sum)
{
    for(int i = 0; i < sum; i ++)
        S[i] = -1;
}

int FindRoot(SetType S[], int x)
{   
    if(S[x] < 0)
        return x;
    else
        return S[x] = FindRoot(S, S[x]);
}

void Union(SetType S[], int root1, int root2)
{
    if(S[root1] > S[root2])
    {
        S[root1] += S[root2];
        S[root1] = root2;
    }
    else 
    {
        S[root2] += S[root1];
        S[root2] = root1;
    }
}

void Check(SetType S[])
{
    int x, y, root1, root2;
    scanf("%d %d\n", &x, &y);
    root1 = FindRoot(S, x - 1);
    root2 = FindRoot(S, y - 1);
    if(root1 == root2)
        printf("yes\n");
    else    
        printf("no\n");
}

void Connect(SetType S[])
{
    int x, y, root1, root2;
    scanf("%d %d\n", &x, &y);
    root1 = FindRoot(S, x - 1);
    root2 = FindRoot(S, y - 1);
    if(root1 != root2)
        Union(S, root1, root2);
}

void Output_Network(SetType S[], int sum)
{
    int counter = 0;
    for(int i = 0; i < sum; i ++)
        if(S[i] < 0)
            counter ++; 
    if(counter == 1)
        printf("The network is connected.\n");
    else if(counter > 1)
        printf("There are %d components.\n", counter);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值