JAVA实践最小生成树---kruskal算法

前言

最小生成树的个人理解:
整条路径没有环,同时任意两点只有一条路
顶点与边数的关系是 边数 = 顶点数 - 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

结尾一点话

这个算法,算是其他思想的结合。
贪心、并查集。可见学习算法不会知道了就好,而是要深入了解其特点,才会清楚该算法/数据结构的特性,综合起来去解决实际问题。

END

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值