zoukankan      html  css  js  c++  java
  • 并查集介绍

      并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

      并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
      
      两种优化方式:
    •   第一个优化是启发式合并。在优化单链表时,我们将较短的表链到较长的表尾,在这里我们可以用同样的方法,将深度较小的树指到深度较大的树的根上。这样可以防止树的退化,最坏情况不会出现。SUB-Find-Set(x)的时间复杂度为O(log N),PROBLEM-Relations时间复杂度为O(N + logN (M+Q))。SUB-Link(a,b)作相应改动。
    •   第二个优化是路径压缩。它非常简单而有效。如图所示,在SUB-Find-Set(1)时,我们“顺便”将节点1, 2, 3的父节点全改为节点4,以后再调用SUB-Find-Set(1)时就只需O(1)的时间。

      案例:

    Description

      若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。

    Input

      第一行:三个整数n,m,p,(n< =5000,m< =5000,p< =5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。 以下m行:每行两个数Mi,Mj,1< =Mi,Mj< =N,表示Mi和Mj具有亲戚关系。 接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。

    Output

      P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。
     
    //    并查集
    
    import java.util.Scanner;
    
    public class Main{
        
        static int tree[];
        static int n;
        static int m;
        static int relationOne;
        static int relationTwo;
        
        public static int findFather(int node){
            if(node!=tree[node]){
                return tree[node]=findFather(tree[node]);
            }
            return node;
        }
        
        public static void main(String args[]){
            
            Scanner reader=new Scanner(System.in);
            n=reader.nextInt();
            m=reader.nextInt();
            tree=new int[n+1];
            relationOne=reader.nextInt();
            relationTwo=reader.nextInt();
            
            for(int i=1;i<=n;i++){
                tree[i]=i;
            }
            
            for(int i=1;i<=m;i++){
                int one=reader.nextInt();
                int two=reader.nextInt();
                int oneFather=findFather(one);
                int twoFather=findFather(two);
                if(oneFather!=twoFather){    //父结点不同
                    if(oneFather>twoFather){    //指向更大的结点
                        tree[twoFather]=oneFather;
                    }else{
                        tree[oneFather]=twoFather;
                    }
                }
            }
            
            int relationOneFather=findFather(relationOne);
            int relationTwoFather=findFather(relationTwo);
            if(relationOneFather==relationTwoFather){
                System.out.println("YES");
            }else{
                System.out.println("NO");
            }
            
        }
        
    }
  • 相关阅读:
    Java的审计项目导入---基于现有的微服务项目上再加个xmsj
    vo中对date格式的时间格式的处理,方便到前台展示
    Java的Maven项目的导入
    [2020-05]测试短信发送记录
    那些年总是记不住的前端写法!
    【HTML+CSS】比较清淡的一个表格。
    C# 里这么写 busiDate.replace('-', ' ').trim(),可以把2020-04-01转为 20200401;java里这么些只能转为2020 04 01……
    radType条件没有用?
    我的程序里面出现了下面的警告:Unreachable code请问是什么原因?该怎么解决呢?
    ubuntu18.04安装Charles及问题
  • 原文地址:https://www.cnblogs.com/chiweiming/p/10702874.html
Copyright © 2011-2022 走看看