杭电oj 1232 畅通工程【并查集】 java

思路总结: 用并查集来 处理已经相互联通的路段,那么需要添加的路数 是就集合个数减一

举一个栗子:如果 1 2 3 相互连通    4 5 6 相互连通    7 8相互连通 那么只需要 2条 就可以让他么全部联通 比如 3 4连通 4 6连通这样就全部连通了,现在就要构造这么一个并查集。

用一维数组来存放节点,初始化数组使下标值等于数组的值,表示当前节点是一个独立的节点,即一开始所有节点的根节点为他本身

查操作:用来查找当前节点的根节点,初始化后array[1]=1,array[2]=2,array[3]=3 。。。。array[i]==i就表示已经查到了根节点了反之不等那么就查他父节点的上一层,直至找到为止。

并操作: 根据输入的值来做合并,比如 1  2 有连通,那么我们先查找 1 2之前的根节点,如果1 2根节点不同就表示他们没有连通,那么把其中一方查到根节点最为另一方的根节点的父节点,此时 1 2 根节点相同表示他们已经连通,合并完成

这里查的过程需要做下 路径压缩,使得这深度变小,同时分支变多。来提高效率 及每一个节点的上一层就是根节点,不需要逐层查找,

代码如下


import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class h1232 {
   
	//找根节点 根节点的特征是arr[i]=i;
	public static int find(int arr[],int i) {
		int z=i;
		//只要当前的节点不是根节点 那就往上寻找根节点
		while(arr[z]!=z) {
			z=arr[z];
		}
		//找到根节点后 把根节点下面的节点做 “平级处理” 
		//上级部门变成兄弟部门(父节点变兄弟节点 2333) 可以理解为根节点分支变多 深度变小 
		int x=i;
		int j;
		//只要当前的节点不是根节点 那就往上寻找根节点
		while(arr[x]!=z) {
			//先记录下此节点的父节点
			j=arr[x];
			//在让当前节点的父节点直接变为根节点
			arr[x]=z;
			//在原先的父节点上继续操作
			x=j;	
		}
		return z;
	}
	public static void join (int arr[],int x,int y) {
		int xz=find(arr,x);
		int yz=find(arr,y);
		if(xz!=yz) {	
			arr[xz]=yz;
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
             Scanner sc=new Scanner(System.in);
             while(sc.hasNext()) {
             int n=sc.nextInt();
             if(n==0)break;
             int m=sc.nextInt();      
             int arr[]=new int[n+1];
             sc.nextLine();
             for(int i=1;i<arr.length;i++) {
            	 arr[i]=i;
             }
             while(m-->0) {
            	 int a=sc.nextInt();
            	 int b=sc.nextInt();
            	 join(arr,a,b);
             }  
            //这里需要在做一次的压缩路径处理     
             for(int i=1;i<=n;i++) {
            	 find(arr,i);
             }
            //如果1 2 3 连通  4 5连通
            //arr 就变 成 1 1 1 4 4 这样 2个集合就出来了 路数为集合数-1
            Set<Integer> s=new HashSet<>();
             for(int i=1;i<arr.length;i++) {
            	s.add(arr[i]); 
             }

            System.out.println(s.size()-1);
             
             }
          
	}

}

图解让你更清晰

https://blog.csdn.net/dellaserss/article/details/7724401

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值