Kruskal算法解决图的最小生成树问题(java)

       最近小哼迷上了《龙门镖局》,从恰克图到武夷山,从张家口到老河口,从迪化到佛山,从蒙自到奉天,迤逦数千里的商道上,或车马,或舟楫,或驼驮,或肩挑,货物往来,钱财递送,皆离不开镖局押运。商号开在哪里,镖局便设在哪里。古代镖局的运镖,就是运货,也就是现代的物流。镖局每到一个新地方开展业务,都需要对运镖途中的绿林好汉进行打点。好说话的打点费就比较低,不好说话的打点费就比较高。现已知城镇地图如下,顶点是城镇编号,边上的值表示这条道路上打点绿林好汉需要的银子数。
在这里插入图片描述
数据给出如下:
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
3 4 9
1 3 2

       第一行有两个数n和m,n表示有n个城市,m表示有m条道路。接下来的m行,每行形如“abc"用来表示一条道路,意思是城市a到城市b需要花费的银子数是C。镖局现在需要选择一些道路进行疏通,以便镖局可以到达任意一一个城镇, 要求是花费的银子越少越好。换句话说,镖局的要求就是用最少的边让图连通( 任意两点之间可以互相到达),其实就是将多余的边去掉。很显然,要想让有n个顶点的图连通,那么至少需要n-1条边。如果一个连通无向图不包含回路,那么这就是一棵树, 其实这里就是求一个图的最小生成树。

import java.util.Scanner;

public class Kruskal {
	class Edge{
		public int u;
		public int v;
		public int w;
		
		public Edge() {}
		
		public Edge(int u, int v, int w) {
			this.u = u;
			this.v = v;
			this.w = w;
		}
	}
	static int n,m,sum,count;
	//快排
	public void quickSort(int left, int right, Edge[] e) {
		int i = left;
		int j = right;
		Edge t = new Edge();
		
		if(left>right) return;
		
		while(i != j) {
			while(e[j].w >= e[left].w && i<j) {
				j--;
			}
			while(e[i].w <= e[left].w && i<j) {
				i++;
			}
			if(i<j) {
				t = e[i];
				e[i] = e[j];
				e[j] = t;
			}
		}
		t = e[i];
		e[i] = e[left];
		e[left] = t;
		
		quickSort(left, i-1, e);
		quickSort(i+1, right, e);
		return;
	}
	//并查集
	public int getf(int i, int[] f) {
		if(f[i] == i) return i;
		else {
			f[i] = getf(f[i], f);
			return f[i];
		}
	}
	
	public boolean merge(int u, int v, int[] f) {
		int t1 = getf(u, f);
		int t2 = getf(v, f);
		if(t1 != t2) {
			f[t2] = t1;
			return true;
		}
		return false;
	}
	
	public static void main(String[] args) {
		Kruskal kruskal = new Kruskal();
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		
		int[] f = new int[n+2];
		Edge[] e = new Edge[m+2];
		
		for(int i=1; i<=m; i++) {
			int u = sc.nextInt();
			int v = sc.nextInt();
			int w = sc.nextInt();
			e[i] = kruskal.new Edge(u,v,w);
		}
		sc.close();
		kruskal.quickSort(1,m,e);
		//并查集数组初始化
		for(int i=1; i<=n; i++) {
			f[i] = i;
		}
		//kruskal算法
		for(int i=1; i<=m; i++) {
			if(kruskal.merge(e[i].u, e[i].v, f)) {
				count ++;
				sum += e[i].w;
			}
			if(count == n-1) break;
		}
		System.out.println(sum);
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值