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

前言

这个算法的普通版本时间复杂度是O(n^2),据说是可优化的。
邻接表+最小堆。然而我并没有去实现。
不过此未经优化的版本适合稠密图,Kruskal解决稀疏图,岂不美哉= =
好吧,我就是懒了

已实现利用最小堆+邻接表优化:
http://blog.csdn.net/xubaifu1997/article/details/52068329

实现功能

实现最小生成树路径长度的计算

中文版参考

/**
 * Prim算法
 * 同样假设所有顶点未连接
    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开始,寻找顶与点1可连接所有的顶点
 *      找到
 *          1→2,权值为1
 *          1→3,权值为2
 *      选择权值最低的2号顶点,连接顶点1、2;
 *
 * 寻找与顶点1、2可连接的所有顶点
 *      找到
 *          1→2(此点排除,2已被作为末端连接)
 *          1→3     权值2
 *          2→3     权值6
 *          2→4     权值11
 *      选择1→3
 * 寻找1、2、3可连接的所有顶点
 *      (排除以1、2、3作为末端的选项)找到
 *          2→4     权值11
 *          3→4     权值9
 *          3→5     权值13
 *       选择3→4
 *  其余点的操作类似
 *
 *  这个过程中唯一的问题是,脑袋会受到最短路径思想的影响
 *  假设
 *      1→2权值1
 *      1→3权值5
 *      选择顶点4时,1→2→4的总长度是12
 *                   1→3→4的总长度为14
 *  碰到这样一开始觉得好奇怪,后来画了个图,发现虽然1到4经过2,单条路径长度最短,总体生成的树却更长
 *  3→1→2→4长度17
 *  2→1→3→4长度15
 *  所以每次选择 距离[任意一个已连接末端顶点] 最短的顶点,而不是距离首个顶点最短的顶点
 *
 *  解决了疑问,马上写代码
 */

代码实现

public class MinGenerationTreePrim {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int Inf = 99;
        int n, m, count, min, minIndex;
        int[][] vertexes;
        boolean[] isConnected;//如果某顶点作为末端顶点被连接,应该为true
        int[] dis;//存储已连接顶点都未连接顶点的最短距离
        int sum = 0;//存储路径长度
        n = in.nextInt();
        m = in.nextInt();
        vertexes = new int[n][n];
        isConnected = new boolean[n];
        dis = new int[n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i == j) {
                    vertexes[i][j] = 0;
                } else {
                    vertexes[i][j] = Inf;
                }
            }
        }

        for (int i = 0, a, b, c; i < m; i++) {
            a = in.nextInt();
            b = in.nextInt();
            c = in.nextInt();
            vertexes[a - 1][b - 1] = c;
            vertexes[b - 1][a - 1] = c;
        }

        //初始化dis数组
        minIndex = 0;
        count = 0;
        for (int i = 0; i < n; i++) {
            dis[i] = vertexes[0][i];
        }
        while (count < n) {
            min = Inf;
            //寻找权值最小的
            for (int i = 0; i < n; i++) {
                if (!isConnected[i] && dis[i] < min) {
                    min = dis[i];
                    minIndex = i;
                }
            }
            sum += min;
            //System.out.println(min);
            isConnected[minIndex] = true;
            count++;
            //在minIndex之前的所有顶点已经对dis更新过了
            //所以只需要更新minIndex顶点到其他顶点是否还有更短的距离
            for (int i = 0; i < n; i++) {
                if (!isConnected[i] && dis[i] > vertexes[minIndex][i]) {
                    dis[i] = vertexes[minIndex][i];
                }
            }
        }
        System.out.println(sum);
    }
}

结果

输入
    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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值