蓝桥杯_算法提高_最小方差生成树(Kruskal算法)

问题描述
给定带权无向图,求出一颗方差最小的生成树。
输入格式
输入多组测试数据。第一行为N,M,依次是点数和边数。接下来M行,每行三个整数U,V,W,代表连接U,V的边,和权值W。保证图连通。n=m=0标志着测试文件的结束。
输出格式
对于每组数据,输出最小方差,四舍五入到0.01。输出格式按照样例。
样例输入
4 5
1 2 1
2 3 2
3 4 2
4 1 1
2 4 3
4 6
1 2 1
2 3 2
3 4 3
4 1 1
2 4 3
1 3 3
0 0
样例输出
Case 1: 0.22
Case 2: 0.00
数据规模与约定
1<=U,V<=N<=50,N-1<=M<=1000,0<=W<=50。数据不超过5组。

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;

/**
 * @author 翔
 *
 */
public class Main {
    private static ArrayList<Double> list=new ArrayList<Double>();

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc=new Scanner(System.in);
        while(true){
            int nodeNum=sc.nextInt();
            int edgeNum=sc.nextInt();
            if(nodeNum==0&&edgeNum==0){
                break;
            }
            list.add(new Test(sc,nodeNum,edgeNum).getMinVariance());
        }
        for(int i=1;i<=list.size();i++){
            System.out.println("Case "+i+": "+new BigDecimal(list.get(i-1)).divide(BigDecimal.ONE,2,BigDecimal.ROUND_HALF_UP));
        }

    }

}
class Test{
    private int nodeNum;//顶点个数
    private int edgeNum;//边条数
    private ArrayList<Edge> edge=new ArrayList<Edge>();//边集
    private ArrayList<Edge> Enew=new ArrayList<Edge>();//最小方差生成树的边集
    private int[] root;//root[i]:代表i节点所在树对应的根节点
    private double minVariance=Double.MAX_VALUE;//最小方差

    public Test(Scanner sc,int nn,int en){
        init(sc,nn,en);
    }

    public double getMinVariance(){
        return minVariance; 
    }

    void init(Scanner sc,int nn,int en){
        nodeNum=nn;
        edgeNum=en;
        root=new int[nodeNum+1];

        for(int i=0;i<edgeNum;i++){
            edge.add(new Edge(sc.nextInt(),sc.nextInt(),sc.nextInt()));
        }

        Collections.sort(edge,new EdgeWeightComparator());//按照边的weight对边排序
        int minAverage=0;//可能的边权均值的最小值
        int maxAverage=0;//可能的边权均值的最大值
        for(int i=0;i<nodeNum-1;i++){
            minAverage+=edge.get(i).weight;
            maxAverage+=edge.get(edgeNum-1-i).weight;
        }

        for(int ave=minAverage;ave<=maxAverage;ave++){
            for(int i=0;i<edgeNum;i++){
                double temp=edge.get(i).weight-(ave*1.0)/(nodeNum-1);
                edge.get(i).cost=temp*temp;
            }
            Collections.sort(edge,new EdgeCostComparator());//按照边的cost对边排序
            initRoot();
            Enew.clear();
            kruskal(ave);
        }
    }

    /**
    Kruskal算法简述:
           假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:
           先构造一个只含 n 个顶点,而边集为空的子图,
           若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。
           之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,
           也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,
           而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
    */
    void kruskal(int ave){
        for(int i=0;i<edgeNum&&Enew.size()<nodeNum-1;i++){
            Edge tempE=edge.get(i);
            if(!isInSameTree(tempE.u,tempE.v)){
                Enew.add(tempE);
                root[tempE.u]=root[tempE.v];
            }
        }

        int realAverage=0;
        double result=0;
        for(int i=0;i<nodeNum-1;i++){
            realAverage+=Enew.get(i).weight;
            result+=Enew.get(i).cost;
        }
        result=result/(nodeNum-1);
        if(realAverage==ave&&result<minVariance){
            minVariance=result;
        }
    }

    //判断两个顶点是否在同一棵树里
    private boolean isInSameTree(int from,int to){
        if(findRoot(from)==findRoot(to)){
            return true;
        }else{
            return false;
        }
    }

    //寻找某节点的根节点
    private int findRoot(int i){
        if(root[i]==i){
            return i;
        }else{
            return root[i]=findRoot(root[i]);
        }
    }

    //在边权均值改变时要重新初始化root数组
    private void initRoot(){
        for(int i=1;i<=nodeNum;i++){
            root[i]=i;
        }
    }


}

class Edge{
    int u;
    int v;
    int weight;//边权重
    int cost;//(weight-average)^2

    public Edge(int u,int v,int weight){
        this.u=u;
        this.v=v;
        this.weight=weight;
    }
}


class EdgeWeightComparator implements Comparator<Edge>{

    public int compare(Edge arg0, Edge arg1) {
        // TODO Auto-generated method stub
        return arg0.weight-arg1.weight;
    }

    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> arg0, Comparator<? super U> arg1) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> comparingDouble(
            ToDoubleFunction<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> nullsFirst(Comparator<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> nullsLast(Comparator<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> reversed() {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparing(Comparator<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public <U extends Comparable<? super U>> Comparator<Edge> thenComparing(
            Function<? super Edge, ? extends U> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public <U> Comparator<Edge> thenComparing(
            Function<? super Edge, ? extends U> arg0, Comparator<? super U> arg1) {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparingDouble(
            ToDoubleFunction<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparingInt(ToIntFunction<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparingLong(ToLongFunction<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}



class EdgeCostComparator implements Comparator<Edge>{

    public int compare(Edge arg0, Edge arg1) {
        // TODO Auto-generated method stub
        if(arg0.cost>arg1.cost){
            return 1;
        }else{
            return -1;
        }
    }

    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> arg0, Comparator<? super U> arg1) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> comparingDouble(
            ToDoubleFunction<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> nullsFirst(Comparator<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T> Comparator<T> nullsLast(Comparator<? super T> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> reversed() {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparing(Comparator<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public <U extends Comparable<? super U>> Comparator<Edge> thenComparing(
            Function<? super Edge, ? extends U> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public <U> Comparator<Edge> thenComparing(
            Function<? super Edge, ? extends U> arg0, Comparator<? super U> arg1) {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparingDouble(
            ToDoubleFunction<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparingInt(ToIntFunction<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public Comparator<Edge> thenComparingLong(ToLongFunction<? super Edge> arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值