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