• 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();
            }
            
            
            
            
        }
    }
  • 相关阅读:
    大话设计模式Python实现-代理模式
    大话设计模式Python实现-装饰模式
    大话设计模式Python实现-策略模式
    设计模式Python实现-简单工厂模式
    Python文件读写机制
    python 多线程剖析
    I/O多路复用-EPOLL探索
    Python学习笔记:魔术方法详解
    Django学习笔记:为Model添加Action
    【Django】Django Debug Toolbar调试工具配置
  • 原文地址:https://www.cnblogs.com/CongLollipop/p/6600370.html
Copyright © 2020-2023  润新知