安慰奶牛.java

来源:互联网 发布:floyed最短路径算法 编辑:程序博客网 时间:2024/06/05 16:54
package A类有价值的回顾的;/* * 最小生成树是什么:连接所有点,而且所有边的权值之和最小1.概览Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪婪算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。2.算法简单描述1).记Graph中有v个顶点,e个边2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边3).将原图Graph中所有e个边按权值从小到大排序4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中                if 这条边连接的两个节点于图Graphnew中不在同一个连通分量中                                         添加这条边到图Graphnew中 */import java.util.Arrays;import java.util.Scanner;class Edge implements Comparable<Edge>{    int S;    int E;    int L;    public int compareTo(Edge o) {        if(this.L > o.L)            return 1;        else if(this.L == o.L)            return 0;        else             return -1;    }}public class 安慰奶牛 {    public static int[] C = new int[100005];//储存每个牧场里的谈话时间    public static int min = 100005;    public static Edge[] e = new Edge[100005];    public static int N,P;    public static int[] far = new int[100005];//根节点指向    private static int find(int x){        int i, k, r;        r = x;        while(far[r] >= 0)//far[r]就是r指向的根节点(farther节点)            r = far[r];   //跳出的时候,far[r]小于0说明r没有根节点,说明她就是最根的节点        k = x;        while(k != r){//让由x节点一直到最根节点中间所有的节点都指向最根节点             i = far[k];//far[k]已经被储存了             far[k] = r;             k = i;        }        return r;// 返回最根节点    }    static void Union(int S,int E){//将两个节点连接        int rS,rE;        int num;        rS = find(S);//S的最根节点        rE = find(E);        num = far[rS] + far[rE];// 最根节点的指向必为负数        if(far[rS] < far[rE]){//负的越多说明需要被连接的更多,更适合做根节点            far[rE] = rS;     //            far[rS] = num;    //        }        else{            far[rS] = rE;            far[rE] = num;        }    }    private static int Kruskal(){        int S,E;        int sumweight = 0,count = 0;        for(int i=0;i<N;i++)//初始化far,这是新建的图中父子关系的初始化            far[i] = -1;        //Arrays.sort(e); 这是不对的,因为这里e的数组中有NULL(100005个并没有完全填充完)        //Arrays.sort(e, 0, P-1); 这样也不对,最后一个没排        Arrays.sort(e, 0, P);//对边的权进行由小到大的排序        for(int i=0;i<P;i++){//贪心算法的核心:从权值最小的路开始依次选择,如果包含了所有的点,就退出            S = e[i].S;                 E = e[i].E;            if(find(S) != find(E)){//如果S的根节点不等于E的根节点,说明没有生成通路,则选择这条边添加到路线中                sumweight += e[i].L;                Union(S,E);                count++;                if(count >= N-1)//如果有了N-1条通路,说明最小生成树生成了                    break;            }        }        return sumweight;    }    public static void main(String[] args){        Scanner sc = new Scanner(System.in);        N = sc.nextInt();//N个牧场        P = sc.nextInt();//P条道路        for(int i=0;i<N;i++){//输入N个牧场奶牛需要谈话的时间            C[i] = sc.nextInt();            if(C[i] < min)//寻找睡觉的地方(最开始当然是需要谈话时间最短的牧场)                min = C[i];        }        for(int i=0;i<P;i++){//输入P条道路行走所需要的时间            e[i] = new Edge();//千万别忘记要new,否则会NoPoint            e[i].S = sc.nextInt()-1;//本身C输入的第一个是指S,E = 1,但是下标却是0            e[i].E = sc.nextInt()-1;//      ↓             e[i].L = sc.nextInt()*2 + C[e[i].S] + C[e[i].E];//这里的时间要考虑所有的时间,包括从一个结点到另一个结点再返回所用时间(包括谈话时间)        }        System.out.println(min + Kruskal());    }}/* * 问题描述   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 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。其实测试用例少了一组,因为路线给有7条,事实只有6条那么如果改为5 61010206301 2 52 3 52 4 123 4 172 5 153 5 6那么结果是178知道了这点之后,我们令边值为l,令节点权值为w,那么每个节点的实际权值可以表示为2*l+w,那么我们可以根据这个来求得最小生成树,然后考虑休息点的选择,只需要选最小的节点即可 */
原创粉丝点击