算法学习之并查集

本文详细介绍了并查集算法的基本概念、实现原理及其应用。通过具体实例,展示了如何使用并查集解决元素间的关系问题,包括初始化、查找真父节点及合并操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.题目描述

给定m组n个元素之间的关系,问这些元素属于个集合

二.输入

10 8

1 2

3 4

5 2

4 6

2 6

8 7

9 7

1 6

2 4


三. 分析

这些元素可能处于这样的状态

1.初始状态即f[i]=i

2.已有父节点并且就是当前状态下真正的父节点

3.已有父节点但并非当前状态下真正的父节点,可能是以前的父节点,其父节点在merge时被合并,但是该节点未被合并。

第三种状态是常是令人担心的,比如在统计集合个数时和判断两个节点是否具有相同的父节点时,针对第一个问题,我们在统计存在几个集合时的方法巧妙,因为所有元素一开始的父节点都是自己,如果一旦存在父节点,那么改状态就会改变,即我们只需统计有多少个节点是自己,那么这就是集合个数,针对第二个问题,我们如果认真考察merge函数就会发现一旦某个节点自己或者其子节点被merge的话那么其父节点状态就会被更新成当前状态下真正的父节点,在小希的迷宫这道题目中,我们希望借助判断需要合并的两个节点是否具有相同的父节点来判断路径的唯一性,但是一开始考虑到两个节点的父节点状态可能并不是真正的父节点而是以前的父节点而导致这个方法没法用,但是如果清楚了我们一但要进行合并就立马回将其状态更新成其真正的父节点,那么这个问题就不存在了,所以我们在merge结束了以后一定还要将所有节点进行一次getf()这样便确保了所有节点的f[]是真正的f[]了

//
//  main.cpp
//  并查集
//
//  Created by 张嘉韬 on 16/3/18.
//  Copyright © 2016年 张嘉韬. All rights reserved.
//

#include <iostream>
#include <cstring>
using namespace std;
int f[50];
void init(int n)
{
    for(int i=1;i<=n;i++) f[i]=i;
}
int getf(int a)
{
    if(f[a]==a) return a;
    else
    {
        f[a]=getf(f[a]);
        return f[a];
    }
}
void merge(int a,int b)
{
    int t1,t2;
    t1=getf(a);
    t2=getf(b);
    if(t1!=t2)
    {
        f[t2]=t1;
    }
}
void print(int n)
{
    for(int i=1;i<=n;i++) cout<<"("<<i<<")"<<f[i]<<" ";
    cout<<endl;
}
int main(int argc, const char * argv[]) {
    freopen("/Users/zhangjiatao/Desktop/input.txt","r",stdin);
    int n,m,a,b,sum;
    sum=0;
    cin>>n>>m;
    init(n);
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b;
        merge(a,b);
        print(n);
    }
    for(int i=1;i<=n;i++)
    {
     f[i]=getf(i);
     }
    for(int i=1;i<=n;i++)
        if(f[i]==i) sum++;
    cout<<sum<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值