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

题目介绍

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了连接两个城镇需要花费的代价。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少花费多少代价就可以完成工程?
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;
        }
    }
}

运行截图

在这里插入图片描述


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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枕石 入梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值