并查集https://mp.csdn.net/postedit/92806830
```java
//在理解kruskal算法之前,请先学习一下,并查集,kruskal算法就是在并查集的基础上,延伸出的
//求最小生成树的算法,并且kruskal算法中的主要函数就是对并查集中函数的沿用
//链接https://blog.csdn.net/aiwo1376301646/article/details/92806830
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
public class Main {
//初始化parent数组和rank数组
public static void chushihua(int[]parent,int []rank) {
for(int i=0;i<parent.length;i++) {
parent[i]=-1;
rank[i]=0;
}
}
//查找一个结点的根节点
public static int find_root(int x,int []parent) {
int x_root=x;
while(parent[x_root]!=-1) {
x_root=parent[x_root];
}
return x_root;
}
//把两个结点放入同一个集合中
public static int union(int x,int y,int []parent,int[]rank) {
int x_root=find_root(x,parent);
int y_root=find_root(y,parent);
if(x_root==y_root) {
return 0;
}
//防止退化为链表
else {
if(rank[x_root]>rank[y_root]) {
parent[y_root]=x_root;
}
else if(rank[x_root]<rank[y_root]) {
parent[x_root]=y_root;
}
else {
parent[x_root]=y_root;
rank[y_root]++;
}
return 1;
}
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
//节点数
int n=in.nextInt();
//边数
int m=in.nextInt();
//parent数组存每一个结点的根节点,-1代表自身就是根节点
int []parent=new int[n];
//rank数组存每一棵树的高度,初始时,每一个结点就是一棵单独的树,高度初始化为0;
int []rank=new int[n];
chushihua(parent,rank);
List<node>list=new ArrayList<node>();
for(int i=0;i<m;i++) {
//in.nextInt()-1的原因是,我的存结点相关信息的数组都是从下标为0开始的,题目是从1开始的
list.add(new node(in.nextInt()-1,in.nextInt()-1,in.nextInt()));
}
Collections.sort(list);
//记录加入集合的边的条数
int k=0;
//记录最小生成树最后一个加入的边的权值
int max=0;
for(int i=0;i<m;i++) {
//因为有n个结点,因此最多加入n-1条边,所有结点就都在一个集合中了
if(k==n-1) {
//此时的i-1,就是上一个i的索引的node的权值就是最后一个加入的边的权值
max=list.get(i-1).quanzhi;
break;
}
//如果这条边的两个结点原来没有在同一个集合中,那么此时的返回值就为1;
//相当于,此时要把这两个结点放入同一个集合中,就是最小生成树中加入这条边。
if(union(list.get(i).from,list.get(i).to,parent,rank)==1) {
k++;
if(k==n-1) {
//此时的i的索引的node的权值就是最后一个加入的边的权值
max=list.get(i).quanzhi;
break;
}
}
}
System.out.println(n-1+" "+max);
}
}
//node类包含三个属性,代表一条边是从哪一个结点到哪一个结点的,权值代表这条路径的长度
//java实现这个class排序,类似于c++语言的struct排序
//因为kruskal算法每一次都是选最小的边加入集合,如果这条边的两个结点已经在同一个集合中了,那么就舍弃这一条边
class node implements java.lang.Comparable<node>{
int from;
int to;
int quanzhi;
public node(int from, int to, int quanzhi) {
super();
this.from = from;
this.to = to;
this.quanzhi = quanzhi;
}
public int compareTo(node o) {
return this.quanzhi-o.quanzhi;
}
}
/*
4 5
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8
3 6
*/
```