萌新学习算法——并查集进阶(最小生成树)

萌新学习算法——并查集进阶(最小生成树)

上面我们通过对并查集的了解,学会了如何判断是两个元素是否在同一个集合,接下来,我们还是通过洛谷的题目来进行解析:lP3366 最小生成树.

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz

输入格式

第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi

输出格式

输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz。
首先要得出最小生成树的方法通常有两种:Prim算法和Kruskal算法两种,在这里我们用的是Kruskal算法来实现的。

思想:

Keuskal的基本思想(贪心策略):先将权值按照从小到大的顺序排列,将每一条边试图加入集合中,若不会生成环,则加入*(判断方法利用并查集的方法来判断来个点是否在同一个集合里面,若在同一个则证明有环,不加入,否则加入)*

首先通过类来包装树的节点Node。

代码实现类Node

class Node {
	int start, end, number;
	//有三个参数的构造函数
	public Node(int start, int end, int number) { 
		this.start = start;
		this.end = end;
		this.number = number;
	}

}

接着利用Comparator接口来实现排序sortNode

class SortNode implements Comparator<Node> {
	public int compare(Node n1, Node n2) {
		//n1.number-n2.number,则返回1,表示从小到大排序
		//n2.number-n1.number,反之从大到小
		return n1.number - n2.number; 
	}
}

find函数:

public static int find(int x)
	{
		if(data[x]<0) return x;
		return data[x]=find(data[x]);
	}

完整代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;

class Node {
	int start, end, number;
	//有三个参数的构造函数
	public Node(int start, int end, int number) { 
		this.start = start;
		this.end = end;
		this.number = number;
	}

}

class SortNode implements Comparator<Node> {
	public int compare(Node n1, Node n2) {
		return n1.number - n2.number;
	}
}

public class Main {
	public static int data[];
	
	public static int find(int x)
	{
		if(data[x]<0) return x;
		return data[x]=find(data[x]);
	}
	
	public static void main(String[] args) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		String str[] = reader.readLine().split(" ");
		int n = Integer.parseInt(str[0]), m = Integer.parseInt(str[1]);
		Node node[] = new Node[m];
		for (int i = 0; i < m; i++) {
			str = reader.readLine().split(" ");
			node[i] = new Node(Integer.parseInt(str[0]), Integer.parseInt(str[1]), Integer.parseInt(str[2]));
		}
		if (n == 1) {
			System.out.println(node[0].number);
			return;
		}
		Arrays.sort(node, new SortNode()); //进行权值排序
		long sum = 0;  //统计最小值
		 data=new int[n+1];
		for(int i=1;i<=n;i++)  //初始化并查集数组
			data[i]=-1;
		int bian=0;  //统计边数
		for (int i = 0; i < m; i++) {
			int s = node[i].start, e = node[i].end; 
			int x=find(s),y=find(e);
			if(x==y)   //产生环,舍弃
				continue;
			sum+=node[i].number; //
			bian+=1; //边数+1
			if(bian==n-1)  //利用最小连通图节点数=边数-1的概念,判断退出条件
				break;
			data[x]+=data[y]; //更新根节点的数据
			data[y]=x;  //更新y的根节点为x
			
		}
		if (bian == n - 1)
			System.out.println(sum);
		else
			System.out.println("orz");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值