问题描述
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 7
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。
这是一道应该是针对C的题目,用java写的代码无论如何都有四组要超时,所有这题重点只要知道实现方法和思路即可
首先假设我们已经生成了一颗树,那么假设我从任意点出发,设为A点,A点是一个特殊的点,因为它需要来回起码两次的访问,这个先放一边,等所有的过程都结束以后我们在考虑。然后我们可以发现 所有的点的访问次数与这个点的度数相等,且举例分析可以发现,所有的边的访问次均为两次,那么我们可以从新定义边的权值,即边本身的w*2加上它连的两个点的权值。最后考虑起点,只要找到权值最小的点,把它加上即可。最小生成树需要并查集,这是不需要说的。
分析结束
import java.util.Arrays;
import java.util.Scanner;
public class Main
{
static int pre[];//并查集的结构
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int P=sc.nextInt();
int px[]=new int[n+1];//点的权值
Edge list[]=new Edge[P];//边的结构,定义见下
int min=px[1]=sc.nextInt();
for(int i=2;i<=n;i++)
{
px[i]=sc.nextInt();
if(min>px[i])
min=px[i];//扎到最小的权值
}
int count=0;//计入加入的边数
for(int i=0;i<P;i++)
{
int x=sc.nextInt();
int y=sc.nextInt();
int w=sc.nextInt();
list[i]=new Edge(x,y,px[x]+px[y]+w*2);//对边的权值的重新定义
}
Arrays.sort(list);//从小到大考虑,实现最小生成树(贪心)
pre=new int[n+1];
int ans=0;
for(int i=1;i<=n;i++)
pre[i]=i;//代表元的初始化
int x,y,tx,ty;
for(int i=0;i<list.length;i++)
{
x=list[i].x;
y=list[i].y;
tx=find(x);
ty=find(y);
if(tx!=ty)//如果代表元不相同则合并
{
count++;
ans+=list[i].w;
pre[tx]=ty;
if(count==n-1)//如果count是n-1,说明已经找到,提前结束
break;
}
}
System.out.println(ans+min);//答案
}
static int find(int x)//寻找代表元
{
return pre[x]==x?x:(pre[x]=find(pre[x]));//这里用了路径压缩,加速下一次的查找,用递归实现,非常简洁
}
}
class Edge implements Comparable<Edge>//这是能对边排序所需要的必要接口
{
int x;
int y;
int w;
Edge(int x ,int y,int w)
{
this.x=x;
this.y=y;
this.w=w;
}
@Override
public int compareTo(Edge k) {
if(w>k.w)return 1;
if(w<k.w)return -1;
return 0;
}
}