蓝桥杯算法提高 集合合并(并查集模板)Java实现

题目

资源限制
内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
  一开始有n个集合,{1},{2}……{n}。
  定义一个操作,给定两个数a,b,用a,b所在的集合的并集代替a和b原来所在的集合。
  求操作之后的集合个数。
输入格式
  第一行是两个自然数n,m(其中m小于n,m和n小于3000),分别表示一开始的集合个数和操作的总数。
  接下来m行,每行两个整数a,b,表示合并a,b所在集合。
输出格式
  一个整数,即最后的集合个数。
样例输入
6 4
1 2
2 3
3 6
4 5
样例输出
2

思路:并查集

并查集的核心就两个点:union和find。
唯一特殊的就是当查的时候,将孩子全记录下来。当查到父亲的时候,直接将父亲和孩子直接相连。
这个算法很简单,只需要一个parent[]数组、union()函数、find()函数即可。Prim算法中,来辨别两个点是否相连过。这是HashMap之类直接存储连接关系不能比的,因为其中连起来一条边的时候,相对性的集合也会相连,这正是并查集所擅长的。

import java.util.HashSet;
import java.util.Scanner;
import java.util.Stack;

public class test
{
	static int[] par;
	public static void main(String[] args) 
	{
		Scanner in =new Scanner(System.in);
		int N=in.nextInt();int M=in.nextInt();
		par=new int[N+1];
		for(int i=0;i<N+1;i++)   //初始化par数组
			par[i]=i;
		
		for(int i=0;i<M;i++)    //开始合并
			union(in.nextInt(), in.nextInt()); 
		HashSet<Integer> hs=new HashSet<Integer>();
		for(int i=1;i<N+1;i++)   //查询并记录父亲,一个父亲只记录一次
			hs.add(find(i));  
		System.out.println(hs.size());
	}

	static  void union(int a ,int b)
	{
		int par_a=find(a);
		int par_b=find(b);
		if(par_a!=par_b)          //如果是同一个父亲不用任何操作
			par[par_b]=par_a;   //是不同父亲,那么随便将一个的父亲改为另一个的
	}
	static int find(int a)
	{
		int j=par[a];
		if(par[j]==j)   //如果他的父亲是根节点,那么直接返回
			return j;
		int t=a;
		Stack<Integer> s=new Stack<Integer>();
		while(par[t]!=t)
		{
			s.add(t);    //使用Stack存放中间遍历的节点,没用递归是放置数据特别大的时候栈溢出,Java的特别容易溢出
			t=par[t];
		}
		while(!s.empty())    //优化,让所有的孩子直接指向父亲
		{
			j=s.pop();
			par[j]=t;
		}
		return t;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值