ALGO-6 安慰奶牛

ALGO-6 安慰奶牛

题目

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

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。

题解

import java.util.Scanner;

public class ALGO_6 {
    static class UnionFind {
        /**
        * 数组,表示并查集所有元素
        */
        private int[] id;

        /**
         * 并查集的元素个数
         */
        int size;

        /**
         * 构造一个新的并查集
         *
         * @param size 初始大小
         */
        public UnionFind(int size) {
            //初始化个数
            this.size = size;
            //初始化数组,每个并查集都指向自己
            id = new int[size];
            for (int i = 0; i < size; i++) {
                id[i] = i;
            }
        }

        /**
         * 查看元素所属于哪个集合
         *
         * @param element 要查看的元素
         * @return element元素所在的集合
         */
        int find(int element) {
            return id[element];
        }

        /**
        * 判断两个元素是否同属于一个集合
        *
        * @param firstElement  第一个元素
        * @param secondElement 第二个元素
        * @return <code>boolean</code> 如果是则返回true。
        */
        public boolean isConnected(int firstElement, int secondElement) {
            return find(firstElement) == find(secondElement);
        }

        /**
         * 合并两个元素所在的集合,也就是连接两个元素
         *
         * @param firstElement  第一个元素
         * @param secondElement 第二个元素
         */
        public void unionElements(int firstElement, int secondElement) {
            //找出firstElement所在的集合
            int firstUnion = find(firstElement);
            //找出secondElement所在的集合
            int secondUnion = find(secondElement);

            //如果这两个不是同一个集合,那么合并。
            if (firstUnion != secondUnion) {
                //遍历数组,使原来的firstUnion、secondUnion合并为secondUnion
                for (int i = 0; i < this.size; i++) {
                    if (id[i] == firstUnion) {
                        id[i] = secondUnion;
                    }
                }
            }
        }
    }

    static class Edge {
        int start;
        int end;
        int weight;

        Edge(int start, int end, int weight) {
            this.start = start;
            this.end = end;
            this.weight = weight;
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int P = sc.nextInt();
        int min = 1000;
        int[] conformTime = new int[N];
        Edge[] edge = new Edge[P];
        for (int i = 0; i < N; i++) {
            conformTime[i] = sc.nextInt();
            if (conformTime[i] < min)
                min = conformTime[i];
        }
        for (int i = 0; i < P; i++) {
            int start = sc.nextInt() - 1;
            int end = sc.nextInt() - 1;
            int length = sc.nextInt();
            edge[i] = new Edge(start, end, 2 * length + conformTime[start] + conformTime[end]);
        }
        sc.close();
        for (int i = 0; i < conformTime.length; i++)
            if (conformTime[i] < min)
                min = conformTime[i];

        Edge[] tree = Kruskal(edge, N);
        System.out.println(count(tree) + min);
    }

    public static int count(Edge[] tree) {
        int sum = 0;
        for (int i = 0; i < tree.length; i++) {
            sum += tree[i].weight;
        }
        return sum;
    }

    public static Edge[] Kruskal(Edge[] edges, int size) {
        Edge[] tree = new Edge[size - 1];
        int index = 0;
        UnionFind uf = new UnionFind(size);
        edges = sort(edges);
        for (int i = 0; index < size - 1; i++) {
            int start = edges[i].start, end = edges[i].end;
            if (uf.find(start) != uf.find(end)) {
                uf.unionElements(start, end);
                tree[index++] = edges[i];
            }
        }
        return tree;
    }

    public static Edge[] sort(Edge[] edge) {
        Edge temp;
        for (int k = edge.length / 2; k > 0; k /= 2) {
            for (int i = k; i < edge.length; i++) {
                for (int j = i; j >= k; j -= k) {
                    if (edge[j - k].weight > edge[j].weight) {
                        temp = edge[j - k];
                        edge[j - k] = edge[j];
                        edge[j] = temp;
                    }
                }
            }
        }
        return edge;
    }

}
posted @ 2022-03-18 13:25  morning-start  阅读(36)  评论(0编辑  收藏  举报