zoukankan      html  css  js  c++  java
  • 并查集——新手学习记录

    好吧,什么垃圾并查集,并查集什么的都是铁憨憨<+__+>

    现在开始复习回忆:(新手,有错误望指正)

    什么叫做并查集,并查集就是一个集合问题,其实最主要的就是知道并查集是一个求解集合数目的问题,具体的操作方法有点飘。

    或者这样理解:——并查集通过一个一维数组来实现,其本质是维护一个森林。(好吧,我也不是很理解),我的理解就是通过一维数组来实现,子节点与父节点之间联系,然后查找集合个数。。。。。。。

    好吧,不清楚,如果看了前面你很懵逼,那就全都忘了吧,,,

    接下来才是正餐:https://blog.51cto.com/ahalei/2348145

    直接上代码:

    题目是杭电的畅通工程:http://acm.hdu.edu.cn/showproblem.php?pid=1232

    #include<stdio.h>
    int fa[1001]={0};
    void zore(int n)//未知量用n表示,初始化
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    
    int find_father(int x)//返回老大,或者说是根节点
    {
        if(fa[x]== x)
            return x;
        else{
            fa[x]=find_father(fa[x]);//优化路径
            return fa[x];
        }
    }
    
    void unions(int n,int m)
    {
        if(find_father(n)!=find_father(m))
            fa[find_father(m)]=find_father(n);
    }
    
    int main()
    {
        int n,m;
        while(scanf("%d %d",&n,&m)&&n)
        {
            int sum=0;
            zore(n);
            while(m--)
            {
                int a,b;
                scanf("%d %d",&a,&b);
                unions(a,b);
            }
            for(int i=1;i<=n;i++)
            {
                if(fa[i]==i)
                    sum++;
            }
            printf("%d
    ",sum-1);
        }
        return 0;
    }

    现在我们把代码拆开来说:

    int main()
    {
        int n,m;//题目中的n代表城市个数,m代表道路数
        while(scanf("%d %d",&n,&m)&&n)
        {
            int sum=0;//用来预装需要修的路数
            zore(n);//调用初始化函数,来使我们的一维数组初始化
            while(m--)//输入m条路
            {
                int a,b;//a,b分别代表道路的起始城市的标号
                scanf("%d %d",&a,&b);
                unions(a,b);//合并有相邻道路的城市,为最后计算道路数做准备:比如最后如果只有两个集合,只需要修一条路;三个集合两条路的思想。
            }
            for(int i=1;i<=n;i++)
            {
                if(fa[i]==i)//寻找到底有几个独立集合
    sum++; } printf("%d ",sum-1); } return 0; } 

     接下来:

    int fa[1001]={0};
    void zore(int n)//初始化作用,这点很重要,因为这个操作为我们接下来的操作提供了数据
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    

     再接下来:

    int find_father(int x)//这个very very重要
    {  //作用是查找根结点,父节点...>如果你看过第一篇文章,你就把他理解成最大的BOOS就好了
        if(fa[x]== x)如果查找点自己就是自己的最大BOOS,则返回
            return x;
        else{
            fa[x]=find_father(fa[x]);//优化路径,其实 是一个递归调用
            return fa[x];//优化过后改变了树的结构,  子节点很多直接变成了根结点       
        }
    }
    

      再接下来再:

    void unions(int n,int m)
    {
        if(find_father(n)!=find_father(m))//合并操作..>其实就是当两个人的老大不一个人的时候,然而却需要建立联系,好吧,这个时候两个人就要开始干架了,最直接的方法是
    fa[find_father(m)]=find_father(n);//直接让两个人的老大来谈话,让一个老大认另一个人的老大为老大,此时他们就属于同一个集合,此时就消除了集合间的隔离,或者说
    //合并了两个集合 }

     

    void unions(int x,int y)
    {
        int b1=find_father(n);//或者变成这样,x市到y市之间有一条路,查询x与y市的老大是谁
        int b2=find_father(m);
        if(b1!=b2)//判断x与y市在不在一个集合
            fa[b1]=b2;//如果不在,合并
    }
    
  • 相关阅读:
    [Effective JavaScript 笔记]第54条:将undefined看做“没有值”
    [Effective JavaScript 笔记]第53条:保持一致的约定
    UDP打洞原理介绍
    Uboot启动分析之Start.S
    MMU
    linux_shell
    SSH2配置
    线程同步
    C#线程基础
    客户端服务器通讯常用的一种方法——Marshal类
  • 原文地址:https://www.cnblogs.com/gti2baby/p/10759760.html
Copyright © 2011-2022 走看看