洛谷 P2330 [SCOI2005]繁忙的都市 kruskal算法 最小生成树 并查集 稀疏图

并查集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
*/
```

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值