继续畅通工程

继续畅通工程
思路:
1. 比”畅通工程”多了个是否已建
2. 那么开始思考了:
可能出现这种情况:当不考虑是否已建时,某颗本来不是最小生成树(A树)的其他生成树(B树)它的总费用是40,
但由于组成B树的部分路已建,这部分路就不需要费用,假如这部分已建的路原本需要的总费用是30,
那么此时B树的建路费用是40-30=10,只需10.
而A树的建路费用是30(小于B树40,这是肯定的),但它还是比B树的实际费用高,这是完全有可能的,因为A树没有考虑已经存在的路
对上述情况演示如下,
这里写图片描述
如上图,假如三条路原本都未建(黑色),明显应该选择10+20=30,这样的建法。
这里写图片描述
如上图,假如有条路已建(红色),明显应该选择10+30,这样的建法,实际只需花费10。
但如果按照常规的过程,边集已经排好序(10,20,30),必然先10入并查集,再20入并查集,结束。错误

3.解决办法:非常简单
把路分成两部分考虑(不需要真的分成两部分存):
(1)先对所有路按费用排序
(2)把已建的加进并查集,费用不计,因为不需要考虑它的费用;
(3)在此基础上,对于剩余的路(未建的)操作就和原先相同了,即进行最小生成树算法

4.代码如下

package com.test09;

import java.util.Arrays;
import java.util.Scanner;
import com.bigDecimal.test;

class Edge3 implements Comparable<Edge3>{
    int a,b;
    int weight;     //维护每条路(边)的费用
    int pass;       //路是否已建

    public Edge3() {
        super();

    }

    public Edge3(int a, int b, int weight, int pass) {
        super();
        this.a = a;
        this.b = b;
        this.weight = weight;
        this.pass = pass;
    }

    public Edge3(int weight) {
        super();
        this.weight = weight;
    }


    @Override
    public int compareTo(Edge3 o) {

        return weight>o.weight? 1:(weight==o.weight? 0 : -1);
    }
}

public class Main076 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int n = sc.nextInt();   //村庄数目
            if (n==0) {
                return;
            }
            int[] tree = new int[n+1];  //题上要求村庄从1计数
            for (int i = 1; i < tree.length; i++) {
                tree[i] = -1;
            }
            //存多条边
            Edge3[] edges = new Edge3[n*(n-1)/2];       
            for (int i = 0; i < edges.length; i++) {
                edges[i] = new Edge3(sc.nextInt(), sc.nextInt(), sc.nextInt(),sc.nextInt());
            }
            Arrays.sort(edges);
            //对于已建的
            for (int i = 0; i < edges.length; i++) {
                if (edges[i].pass==1) {
                    int a = findRoot(tree, edges[i].a);
                    int b = findRoot(tree, edges[i].b);
                    if(a!=b){
                        tree[a] = b;
                    }
                }
            }
            //对于剩余的路进行最小生成树算法
            int ans = 0;            //此时才开始计总费用
            for (int i = 0; i < edges.length; i++) {
                if (edges[i].pass==0) {
                    int a = findRoot(tree, edges[i].a);
                    int b = findRoot(tree, edges[i].b);
                    if(a!=b){
                        tree[a] = b;
                        ans+=edges[i].weight;
                    }
                }
            }
            //本例默认总可以找到最小生成树
            System.out.println(ans);
        }
    }

    private static int findRoot(int[] tree,int x) {
        if(tree[x]==-1){
            return x;
        }else{
            int tmp = findRoot(tree, tree[x]);
            tree[x] = tmp;
            return tmp;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值