Union/find--不相交集类(并查集)

不相交集类 ,可以用来解决等价问题,实现起来简单,可以只使用一个数组。

用一个数组id[N]  记录N个触点,初始化Id[i] =i;

实现动态链接的时候,遍历这个数组,如果p和q的id[p] =id[q] 那么不用管,否则要将pq链接起来,使用uion方法,也就是将p的分量重命名为id[q]。

具体实现如下:

package p2;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class UnionFind {
    public int [] id;
    public int count;

    public UnionFind(int N){ //初始化数组  表示有N个触点

        count =N;
        id = new int[N];
        for(int i=0;i<N;i++){
            id[i] =i;
        }
    }
    /**
     *
     * @param p
     * @return
     */
    public int find(int p){

        return id[p];
    }

    public void union(int p,int q){
        int pid=find(p);
        int qid = find(q);
        if(pid==qid) return ;
        //将所有被标为p的分量的 标为Q
        for(int i=0;i<id.length;i++){
            if(id[i] == pid) id[i] =qid;
        }
        count--;
    }
    /**
     * 若果pq是联通的就返回true
     * @param p
     * @param q
     * @return
     */
    public boolean connected(int p,int q){

        return find(p)==find(q);
    }

    /**
     * 返回连通分量的数目
     * @return
     */
    public int  count(){

        return count;
    }

    public static void main(String [] args){
        try {
            Scanner sc = new Scanner(new File("fortest"));
            int N =sc.nextInt();
            //System.out.println(N);
            UnionFind uf = new UnionFind(N);
            while(sc.hasNextLine()){
                int p = sc.nextInt();
                int q =sc.nextInt();
                if(uf.find(p)==uf.find(q)) continue;
                uf.union(p, q);
                System.out.println("建立连接"+p+"和"+q);
            }
            System.out.println(uf.count+"还没有连接上的components");
            System.out.println(uf.connected(0, 9));

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

测试集fortest如下:

10
4 3
3 8
6 5
9 4
2 1
8 9
5 0
7 2
6 1
1 0
6 7
7 8

以上内容参考算法 第四版。

这种是最简单的quik-find,但是查找效率不高,需要遍历整个数组。后面会介绍quick-union 森林表示以及加权的quick-union.

顺便写一个quick-find 的应用题。修公路的题目盗用同学的博客题的图。哈哈

用java实现思路就是用unionfind  N 个村庄,就是N个触点,从1-N 现在连通的有M条路,用A和B表示,那么如果需要将所有的村庄连通,则就是说这些村庄必须两两相连。那么首先,我们将已知的连通数记录下来,然后再将相连的子块标记,count,最后-1就是需要多修的公路数。利用以上的API,代码如下:

package p2;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class UnionFind {
    public int [] id;
    public int count;

    public UnionFind(int N){ //初始化数组  表示有N个触点

        count =N;
        id = new int[N+1];
        for(int i=1;i<=N;i++){
            id[i] =i;
        }
    }
    /**
     *
     * @param p
     * @return
     */
    public int find(int p){

        return id[p];
    }

    public void union(int p,int q){
        int pid=find(p);
        int qid = find(q);
        if(pid==qid) return ;
        //将所有被标为p的分量的 标为Q
        for(int i=0;i<id.length;i++){
            if(id[i] == pid) id[i] =qid;
        }
        count--;
    }
    /**
     * 若果pq是联通的就返回true
     * @param p
     * @param q
     * @return
     */
    public boolean connected(int p,int q){

        return find(p)==find(q);
    }

    /**
     * 返回连通分量的数目
     * @return
     */
    public int  count(){

        return count;
    }

    public static void main(String [] args){
         int ans=0;
        try {
            Scanner sc = new Scanner(new File("fortest"));

            int N =sc.nextInt();
            int mark [] = new int[N+1];
            //System.out.println(N);
            int M = sc.nextInt();
            UnionFind uf = new UnionFind(N);
            while(sc.hasNextLine()){
                int p = sc.nextInt();
                int q =sc.nextInt();
                //if(uf.find(p)==uf.find(q)) continue;
                uf.union(p, q);
                System.out.println("建立连接"+p+"和"+q);
            }
            for(int i=1;i<=N;i++){  //标记连通块的节点
                mark[uf.find(i)] =1;
            }
            for(int i=1;i<=N;i++){
                if(mark[i]!=0) ans++;
            }
            System.out.println("还需要修"+(ans-1));

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
时间: 2024-10-06 13:34:15

Union/find--不相交集类(并查集)的相关文章

不相交集类(并查集)

并查集 就是只有合并和 查找操作的一种数据结构  很简单,主要判断一个元素是否在一个集合里 主要应用在最小生成树(Kruskal算法),看到图的时候会将实现代码贴上 package chapter8; /** * 类名:DisjSets 说明:实现并查集 按高度求并,路径压缩 s[i]代表i的父节点 */ public class DisjSets { public DisjSets(int numElements) { s = new int[numElements]; for (int i

poj1988-种类并查集

题意:有N个立方体(1<=N <=30,000),相应地初始时每个立方体放在一个栈中,有两种操作:1.M X Y:把包含第X个立方体的栈中的所有立方体当做一个整体拿出来压入包含第Y个立方体的栈中(即是放在Y栈中的栈顶):2.C X:询问编号为X的立方体下有几个立方体. 思路:把每次1操作后的栈底元素当做根节点.记录栈中元素到根节点的距离h[],记录栈中元素的子节点个数ch[].Find()路径压缩的时候更新的当前节点到根节点的距离h[]即是h[]加上其原父节点到根节点的距离.合并两个栈元素的时

并查集(Java实现)

并查集:用数组实现 思路 数组里存的数字代表所属的集合.比如arr[4]==1;代表4是第一组.如果arr[7]==1,代表7也是第一组.既然 arr[4] == arr[7] == 1 ,那么说明4 和 7同属于一个集合, 代码 /** * 数组实现并查集,元素内数字代表集合号 */ public class UnionFind { /** * 数组,表示并查集所有元素 */ private int[] id; /** * 并查集的元素个数 */ private int size; /** *

并查集(不相交集)的Union操作

在并查集(不相交集)中附加操作\(Deunion\),它实现的功能是取消最后一次\(Union\)的操作. 实现思想 初始化一个空栈,将每一次的\(Union\)操作的两个集合的根和其值\(Push\)入栈:若执行\(Deunion\)操作时,只需要对栈进行\(Pop\)操作即可.在没有路径压缩时,这个策略是有效的:若并查集(不相交集)实现了路径压缩,将使得\(Deunion\)操作很难进行,因为路径压缩有很大的概率将本来属于一个根下的元素连接到另一个根,若此时执行\(Union\)操作时,很难

并查集(union/find)

在计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构: Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集. Union:将两个子集合并成同一个集合. 因为它支持这两种操作,一个不相交集也常被称为联合-查找数据结构(union-find data structure)或合并-查找集合(merge-find set

并查集类的c++封装,比较union_find algorithm四种实现方法之间的性能差别

问题描述: 在计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构: Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集: Union:将两个子集合并成同一个集合: 实现并查集的关键是实现union-find algorithm, 本文根据常用的四种算法,实现了这个类,具体算法实现请参看维基百科: 制造测试数据集,

并查集类的c++封装,比較union_find algorithm四种实现方法之间的性能区别

问题描写叙述: 在计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构: Find:确定元素属于哪一个子集.它能够被用来确定两个元素是否属于同一子集: Union:将两个子集合并成同一个集合: 实现并查集的关键是实现union-find algorithm, 本文依据经常使用的四种算法,实现了这个类,详细算法实现请參看维基百科: 制造測试

使用并查集来维护不同的类关系

我们理解并查集这个数据结构的时候不要过于死板,我们要知道 并查集是用来维护关系的,而不是单纯一味去归并,归并,归并 下面给出一个问题尝试用并查集来解决:一共有两个类,然后告诉你若干组数据,每一组数据的两个元素不是一类的,然后在线判断两个元素是否是同一类 这个时候如果你只会归并就行不通的,还需要一些特殊的处理 我们需要在并查集的那个数组的基础之上,需要另一个数组来记录这种特殊的现象 int set[maxn],a[maxn]; //a表示这个节点和父节点的关系,0表示相同1表示不同 接下来我们的路

HDU 1035 Robot Motion Union Find 并查集题解

本题的类型我一看就想到使用并查集解了,因为要查找是否有环,这是并查集的典型用法. 但是由于本题数据实在是太水了,故此有人使用直接模拟都过了.这让本题降了个档次. 这里使用并查集解.而且可以根据需要简化并查集函数,代码还是很好打的. #include <stdio.h> #include <vector> #include <string.h> #include <algorithm> #include <iostream> #include &l