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;
}
}