《算法》学习笔记(1)——Union-found

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/88837178

动态连通性问题:

输入一列整数对,其中每个整数都表示一个某种类型的对象,一对整数p,q可以被理解为 是相连的,即p和q属于同一个等价类。
编写一个程序来过滤掉序列中所有无意义的整数对(两个整数均来自于同一个等价类中)。换句话说,当程序从输入中读取了整数对p q时,如果已知p和q是属于同一个等价类则忽略,如果已知的所有整数对都不能说明p和q是相连的,那么则将这一对整数输出。

一:设计API

  • UF(int N):以整数标识(0到N-1)连通分量,初始化N个触点
  • void union(int p, int q):在p和q之间添加一条连接
  • int find(int p):P所在的分量的标识符(0到N-1)
  • boolean connected(int p, int q):如果p和q存在于同一个分量中则返回true
  • int count():连通分量的数量

二:设计数据结构,确定实例变量

  • 用整数表示N个结点
  • 用以结点为索引的数组id[]表示结点的分量。一开始每个结点都只含有它自己,初始化 id[i] = i (0<i<N-1)
  • 用分量中的最后一个结点的名称作为分量的标识符
  • 用一个数组,表示结点的权数,也就是结点的分量大小

三:设计算法

1:判断两个结点是否属于同一连通分量:
  1. 获取结点A和结点B所在连通分量的最后一个结点
  2. 如果两个分量的最后一个结点相同,则证明A和B处于同一个分量
2:连接结点的分量 —— 无权值
  1. 获取准备连接的结点A所在分量的最后一个结点C
  2. 将连接的结点B所在下标,作为结点C的当前分量值,即 id[A] = B
  3. 相当于将A结点的分量与B连接
3:连接结点的分量 —— 带权值
  1. 获取结点A所在分量的最后一个结点C,结点B所在分量的最后一个结点D
  2. 判断AC分量的总大小和BD分量的总大小,把小的分量连向大的分量
  3. 将连接的大结点所在下标,作为小结点的当前分量值
  4. 更新大结点的分量总大小
实现一:
/**
 * 动态连通性问题
 */
public class UnionFound {
    //结点个数
    private int size;
    //记录每个结点的连通分量
    private int[] id;
    //保存结点,方便判断后连通
    private int node;
	
    public UnionFound(int size) {
        this.size = size;
        id = new int[size];
        node = -1;
        for (int i = 0; i < id.length; i++) {
            id[i] = i;
        }
    }

    //连通两个结点
    public void union(int p,int q){
        id[node] = q;
        if(size>1)
            size--;
    }

    //获得结点所在连通分量的末端
    public int find(int p){
        while (id[p] != p)
            p = id[p];
        node = p;
        return p;
    }

    //判断是否连通
    public boolean connect(int p,int q){
        return find(q) == find(p);
    }


    //获得结点所在连通分量的数量
    public int conunt(){
        return size;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        UnionFound uf = new UnionFound(n);
        scanner.nextLine();
        String s = scanner.nextLine();
        while (!s.equals(""))
        {
            String[] strings = s.split(" ");
            int p  = Integer.parseInt(strings[0]);
            int q  = Integer.parseInt(strings[1]);
            if(uf.connect(p,q))
            {
                s = scanner.nextLine();
                continue;
            }
            uf.union(p,q);
            System.out.println(p+" "+q);
            s = scanner.nextLine();

        }
        System.out.println("总共有"+uf.conunt()+"个连通分量");
    }


}
实现二:

/**
 * 动态连通性问题
 */
public class UnionFound {
    //结点个数
    private int size;
    //记录每个结点的连通分量
    private int[] id;
    //保存两个结点,方便连通
    private int nodeA,nodeB;
    //记录每个结点的连通分量的大小
    private int[] power;

    public UnionFound(int size) {
        this.size = size;
        nodeA = nodeB = -1;
        id = new int[size];
        for (int i = 0; i < id.length; i++) {
            id[i] = i;
        }
        power = new int[size];
        for (int i = 0; i < power.length; i++) {
            power[i] = 1;
        }
    }

    //连通两个结点
    public void union(int p,int q){
        if(power[nodeA] < power[nodeB])
        {
            id[nodeA] = q;
            power[nodeB]+=power[nodeA];
        }
        else
        {
            id[nodeB] = p;
            power[nodeA]+=power[nodeB];
        }
        if(size>1)
            size--;
    }

    //获得结点所在连通分量的末端
    public int find(int p){
        while (id[p] != p)
            p = id[p];
        return p;
    }

    //判断是否连通
    public boolean connect(int p,int q){
        nodeA = find(p);
        nodeB = find(q);
        return nodeA == nodeB;
    }


    //获得结点所在连通分量的数量
    public int conunt(){
        return size;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        UnionFound uf = new UnionFound(n);
        scanner.nextLine();
        String s = scanner.nextLine();
        while (!s.equals(""))
        {
            String[] strings = s.split(" ");
            int p  = Integer.parseInt(strings[0]);
            int q  = Integer.parseInt(strings[1]);
            if(uf.connect(p,q))
            {
                s = scanner.nextLine();
                continue;
            }
            uf.union(p,q);
            System.out.println(p+" "+q);
            s = scanner.nextLine();

        }
        System.out.println("总共有"+uf.conunt()+"个连通分量");
    }


}

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/88837178