前言
最小生成树的个人理解:
整条路径没有环,同时任意两点只有一条路
顶点与边数的关系是 边数 = 顶点数 - 1
路径最短
最小生成树的用途比较实际,比如如何以最短的路径走8个地方一遍,且不重复。
而Kruskal算法就可以解决此问题。
实现功能
基于Kruskal算法实现对现有的无向图生成最小树
并计算整条路径的长度输出
中文版参考
/**
* 最小生成树算法--Kruskal算法:
* 原理:
* 将每一条边按权值从小到大排序
* 假设所有顶点尚未连接
* 然后按权值对它们进行连接
* 若已连通,那么跳过
*
* 判断是否已连通:可通过深度/广度/并查集算法
* 使用并查集解决效率更高
*
* 6 9
* 2 4 11
* 3 5 13
* 4 6 3
* 5 6 4
* 2 3 6
* 4 5 7
* 1 2 1
* 3 4 9
* 1 3 2
*
* 按权值排序
* 1 2 1
* 1 3 2
* 4 6 3
* 5 6 4
* 2 3 6
* 4 5 7
* 3 4 9
* 2 4 11
* 3 5 13
*
* 假设以上各个顶点之间尚未连接
* 1 - 2权值最小
* 判断1和2是否已连接,否,连接1-2
* 1 - 3,判断是否已连接,否,连接1-3
* 4 - 5,判断是否已连接,否,连接4-6
* 连接5-6
* 尝试连接2-3时,发现可以2->1->3,表示2与3是连通的,跳过连接2-3
* 其他同理,若能到达的两个点则跳过
*
* 算法都是之前学过的并查集,排序那块可以自己写个快排排着玩- -
* 我就偷懒了,直接用了java自带的(逃
*/
代码实现
public class MinGenerationTree {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n, m, sum = 0, count = 0;
int[] f;
Edge[] edges;
n = in.nextInt();
m = in.nextInt();
f = new int[n + 1];
edges = new Edge[m];
for (int i = 1; i <= n; i++) {
f[i] = i;
}
for (int i = 0; i < m; i++) {
edges[i] = new Edge(in.nextInt(), in.nextInt(), in.nextInt());
}
Arrays.sort(edges);
for (int i = 0; i < edges.length; i++) {
if (merge(f, edges[i].getFrom(), edges[i].getTo())) {
sum += edges[i].getWeight();
count++;
}
if (count == n - 1) {
break;
}
}
System.out.println(sum);
}
public static boolean merge(int[] f, int a, int b) {
int t1, t2;
t1 = getRoot(f, a);
t2 = getRoot(f, b);
if (t1 != t2) {
f[t2] = t1;
return true;
}
return false;
}
public static int getRoot(int[] f, int i) {
if (f[i] == i) {
return i;
} else {
f[i] = getRoot(f, f[i]);
return f[i];
}
}
}
class Edge implements Comparable {
private int from, to, weight;
Edge(int from, int to, int weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
public void setFrom(int from) {
this.from = from;
}
public void setTo(int to) {
this.to = to;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getFrom() {
return from;
}
public int getTo() {
return to;
}
public int getWeight() {
return weight;
}
@Override
public int compareTo(Object o) {
return this.weight - ((Edge)o).weight;
}
}
结果
输入
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
输出
19
结尾一点话
这个算法,算是其他思想的结合。
贪心、并查集。可见学习算法不会知道了就好,而是要深入了解其特点,才会清楚该算法/数据结构的特性,综合起来去解决实际问题。