【短学期算法作业】Kruskal算法的实现(并查集)

分类专栏:
用Java写数据结构

文章标签:
Java
原创

题目介绍

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了连接两个城镇需要花费的代价。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少花费多少代价就可以完成工程? Input 输入包含多组数据,对于每组测试数据: 第一行包含两个正整数N和M(0 <=N <=1000,0 < M < 5000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以1~N编号。 接下来是M行道路信息。每一行有三个整数A,B,X(0 < A,B <= N ,0 < X < 10000),表示可以在城镇A和城镇B之间建一条花费为X的双向道路。保证数据可以完成工程。 Output 对于每组数据,输出完成工程需要花费的最少代价。 Sample Input 3 3 1 2 3 1 3 1 2 3 2 Sample Output 3

题目思路

利用并查集来维护城市间是否连通。每次寻找花费最少且未被标记的道路并且标记,如果该道路两头未连通,则累加到总花费中。直至找不到输出总花费。

具体代码

package com.dreamchaser;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * kruskal算法的实现(并查集)
 */
public class test5 {
    /**
     * 记录城市连通情况
     * 下标为零的不算数
     */
    static int[] city;
    static List<Road> roads = new ArrayList<Road>();
    /**
     * 现有城镇的数目
     */
    static int n;
    /**
     * 能修建的道路的数目
     */
    static int m;

    public static void main(String[] args) {
        input();
        System.out.println("最少所需费用为:");
        System.out.println(caculate());

    }

    /**
     * 计算费用
     * 按价格遍历所有可行的道路,将未连通的道路费用加上并合并所在集合
     * @return
     */
    private static int caculate() {
        int total=0;
        Road road=findMin();
        while (road!=null){
            if (merge(road.begin, road.end)!=0){
                total+=road.money;
            }
            //标记已经遍历
            road.flag=true;
            road=findMin();
        }
        return total;
    }

    /**
     * 寻找最短可行路径
     * @return
     */
    private static Road findMin() {
        Road minRoad=null;
        for (Road road:roads){
            if (minRoad==null){
                if (!road.flag){
                    minRoad=road;
                }
            }else if(!road.flag&&road.money< minRoad.money){
                minRoad=road;
            }
        }
        return minRoad;
    }


    private static void input() {
        Scanner scanner = new Scanner(System.in);

        n = scanner.nextInt();

        m = scanner.nextInt();

        //输入道路信息
        for (int i = 0; i < m; i++) {
            Road road = new Road(scanner.nextInt(), scanner.nextInt(), scanner.nextInt());
            roads.add(road);
        }


        city = new int[n+1];
    }

    /**
     * 寻找根节点
     *
     * @param i
     * @return
     */
    private static int findUnion(int i) {
        /**
         * 合并集的根
         */

        if (city[i] != 0) {
            int root = findUnion(city[i]);
            //路径压缩
            city[i] = root;
            return root;
        } else {
            return i;
        }
    }

    /**
     * 合并集合
     * 如果两个属于同一个集合则返回null,否则返回根节点
     * @param x
     * @param y
     * @return
     */
    private static int merge(int x, int y) {
        int root1 = findUnion(x);
        int root2 = findUnion(y);
        if (root1 != root2) {
            city[root2] = root1;
            return root1;
        } else {
            return 0;
        }

    }

    static class Road {
        int begin;
        int end;
        int money;
        /**
         * 标记有没有走过
         */
        Boolean flag=false;
        public Road(int begin, int end, int money) {
            this.begin = begin;
            this.end = end;
            this.money = money;
        }
    }
}

运行截图

在这里插入图片描述

记录点滴,乐于分享,转载请注明出处。

愿我们能以梦为马,不负人生韶华! 与君共勉!

  • 作者:金昊霖
  • 发表时间:2020-7-04
  • 版权声明:自由转载-非商用-非衍生-保留署名(创意共享3.0许可证)
  • 评论

    留言