蓝桥杯_算法训练_安慰奶牛(用Kruskal、Prim算法分别实现)

来源:互联网 发布:python mobi 下载 编辑:程序博客网 时间:2024/06/06 04:17

问题描述
Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路。
道路被用来连接N个牧场,牧场被连续地编号为1到N。每一个牧场都是一个奶牛的家。
FJ计划除去P条道路中尽可能多的道路,但是还要保持牧场之间 的连通性。
你首先要决定那些道路是需要保留的N-1条道路。
第j条双向道路连接了牧场Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N; Sj != Ej),而且走完它需要Lj的时间。
没有两个牧场是被一条以上的道路所连接。
奶牛们非常伤心,因为她们的交通系统被削减了。
你需要到每一个奶牛的住处去安慰她们。每次你到达第i个牧场的时候(即使你已经到过),你必须花去Ci的时间和奶牛交谈。
你每个晚上都会在同一个牧场(这是供你选择的)过夜,直到奶牛们都从悲伤中缓过神来。
在早上 起来和晚上回去睡觉的时候,你都需要和在你睡觉的牧场的奶牛交谈一次。
这样你才能完成你的 交谈任务。假设Farmer John采纳了你的建议,请计算出使所有奶牛都被安慰的最少时间。

输入格式
第1行包含两个整数N和P。
接下来N行,每行包含一个整数Ci。
接下来P行,每行包含三个整数Sj, Ej和Lj。

输出格式
输出一个整数, 所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间)。
样例输入
5 6
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
样例输出
176
数据规模与约定
5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。

Kruskal算法简述:
假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:
先构造一个只含 n 个顶点,而边集为空的子图,
若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。
之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,
也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,
而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。

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 int nodeNum;//节点个数    private static int edgeNum;//边数    private static int[] C;//节点权值    private static int Cmin;//最小节点权值    private static ArrayList<Edge> edges=new ArrayList<Edge>();//边集合    private static ArrayList<Edge> Enew=new ArrayList<Edge>();//Kruskal算法中的Enew    private static int[] root;//root[i]:代表i节点所在树对应的根节点    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        init();        kruskal();        System.out.println(caculate());    }    //计算所需要的总时间    private static int caculate(){        int sum=0;        for(int i=0;i<Enew.size();i++){            sum+=Enew.get(i).weight;        }        return sum+Cmin;    }    //Kruskal算法的主要步骤    private static void kruskal(){        for(int i=0;i<edges.size()&&Enew.size()<nodeNum-1;i++){            Edge edge=edges.get(i);            if(!inSameTree(edge.from,edge.to)){                Enew.add(edge);                root[edge.to]=root[edge.from];            }        }    }    //判断两个顶点是否在同一棵树里    private static boolean inSameTree(int from,int to){        if(findRoot(from)==findRoot(to)){            return true;        }else{            return false;        }    }    //寻找某节点的根节点    private static int findRoot(int i){        if(root[i]==i){            return i;        }else{            return root[i]=findRoot(root[i]);        }    }    //初始化各参数的值    private static void init(){        Scanner sc=new Scanner(System.in);        nodeNum=sc.nextInt();        edgeNum=sc.nextInt();        C=new int[nodeNum+1];        root=new int[nodeNum+1];        for(int i=1;i<=nodeNum;i++){            C[i]=sc.nextInt();            root[i]=i;        }        findCmin();//寻找出最小节点权值        for(int i=0;i<edgeNum;i++){            Edge edge=new Edge(sc.nextInt(),sc.nextInt(),sc.nextInt());            edges.add(edge);        }        //重新计算边权!!!!重点!!!!!!!!!!!!        for(int i=0;i<edgeNum;i++){            edges.get(i).weight=edges.get(i).weight*2+C[edges.get(i).from]+C[edges.get(i).to];        }        Collections.sort(edges,new EdgeComparator());//按照权值对边集合排序        sc.close();    }    //寻找出最小节点权值    private static void findCmin(){        int min=C[1];        for(int i=2;i<=nodeNum;i++){            if(C[i]<min){                min=C[i];            }        }        Cmin=min;    }}class Edge{    int from;    int to;    int weight;    public Edge(int from,int to,int weight){        this.from=from;        this.to=to;        this.weight=weight;    }}class EdgeComparator 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;    }}

Prim算法简述
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew= {x},其中x为集合V中的任一节点(起始点),Enew= {},为空;
3).重复下列操作,直到Vnew= V:
a.在集合E中选取权值最小的边

import java.util.ArrayList;import java.util.Scanner;/** * @author 翔 * */public class Main {    private static int nodeNum;//节点个数    private static int edgeNum;//边数    private static int[] C;//节点权值    private static int Cmin;//最小节点权值    private static ArrayList<Edge> edges=new ArrayList<Edge>();//边集合    private static ArrayList<Edge> Enew=new ArrayList<Edge>();//Prim算法中的Enew    private static ArrayList<Integer> V_Vnew=new ArrayList<Integer>();//Prim算法中的V-Vnew    private static ArrayList<Integer> Vnew=new ArrayList<Integer>();//Prim算法中的Vnew    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        init();        prim();        System.out.println(caculate());    }    //计算所需要的总时间    private static int caculate(){        int sum=0;        for(int i=0;i<Enew.size();i++){            sum+=Enew.get(i).weight;        }        return sum+Cmin;    }    //Prim算法的主要步骤    private static void prim(){        for(int i=2;i<=nodeNum;i++){            int min=Integer.MAX_VALUE;            Edge temp=null;            for (int j = 0; j < edges.size(); j++) {                if (((V_Vnew.contains(edges.get(j).from)                        && Vnew.contains(edges.get(j).to))                        || (Vnew.contains(edges.get(j).from)                        && V_Vnew.contains(edges.get(j).to)))                        && edges.get(j).weight < min) {                    temp = edges.get(j);                    min = temp.weight;                }            }            if(V_Vnew.contains(temp.to)){                V_Vnew.remove(new Integer(temp.to));                Vnew.add(temp.to);            }else{                V_Vnew.remove(new Integer(temp.from));                Vnew.add(temp.from);            }            edges.remove(temp);            Enew.add(temp);                 }       }    //初始化各参数的值    private static void init(){        Scanner sc=new Scanner(System.in);        nodeNum=sc.nextInt();        edgeNum=sc.nextInt();        C=new int[nodeNum+1];        for(int i=1;i<=nodeNum;i++){            C[i]=sc.nextInt();            V_Vnew.add(i);        }        int CminFlag=findCmin();//寻找出C[]数组中值最小的数对应的下标        V_Vnew.remove(new Integer(CminFlag));        Vnew.add(CminFlag);        for(int i=0;i<edgeNum;i++){            Edge edge=new Edge(sc.nextInt(),sc.nextInt(),sc.nextInt());            edges.add(edge);        }        //重新计算边权!!!!重点!!!!!!!!!!!!        for(int i=0;i<edgeNum;i++){            edges.get(i).weight=edges.get(i).weight*2+C[edges.get(i).from]+C[edges.get(i).to];        }        sc.close();    }    //寻找出C[]数组中值最小的数对应的下标    private static int findCmin(){        int min=C[1];        int flag=1;        for(int i=2;i<=nodeNum;i++){            if(C[i]<min){                min=C[i];                flag=i;            }        }        Cmin=min;        return flag;    }}class Edge{    int from;    int to;    int weight;    public Edge(int from,int to,int weight){        this.from=from;        this.to=to;        this.weight=weight;    }}
0 0
原创粉丝点击