安慰奶牛—最小生成树

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

输入格式
第 1 行: 用空格隔开的两个整数N和P
第 2..N+1 行: 第i+1行包含了一个整数: C_i第 N+2..N+P+1 行:
第 N+j+1 行包含用空格隔开的三个整数: S_j, E_j 和 L_j

输出格式
第 1 行: 一个整数, 所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间).

样例
样例输入
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
4 5 12

样例输出
176

样例解释
从牧场4起床, 然后按照 4, 5, 4, 2, 3, 2, 1, 2, 4 的顺序来访问奶牛们, 总共需要176个单位的时间.

数据范围与提示
对于100%的数据:
5 <= N <= 10000
N-1 <= P <= 100000
1 <= S_j <= N 1 <= E_j <= N S_j <>E_j
0 <= L_j <= 1,000
1 <= C_i <= 1,000

思路:这个题实际上是个变形的最小生成树的题,他给每个顶点也加上了花费,但本质上不变,实际上只是每一条路的花费改变了,仔细模拟几遍应该能发现利用每一条边和两个端点能找到每一条边的实际花费。因为要回到那个点睡觉,所以出发之后还需要返回,那么每条边是走了两次,然后再加上两个端点,实际花费是  a[i].z=d[a[i].x]+d[a[i].y]+a[i].z*2;

很简单のACcode:

#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int n,p,ans,sum=0x3fff,d[N],fa[N];
struct stu{
	int x,y,z;
}a[N];
bool cmp(stu a,stu b){
	return a.z<b.z;
}
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
void kruskal(){
	sort(a+1,a+1+p,cmp);
	for(int i=1;i<=p;i++){
		int fx=find(a[i].x);
		int fy=find(a[i].y);
		if(fx!=fy){
			fa[fx]=fy;
			ans+=a[i].z;
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>p;
	for(int i=1;i<=n;i++){
		cin>>d[i];
		if(sum>d[i]) sum=d[i];
		fa[i]=i;
	}
	for(int i=1;i<=p;i++){
		cin>>a[i].x>>a[i].y>>a[i].z;
		a[i].z=a[i].z*2+d[a[i].x]+d[a[i].y];
	}
	kruskal();
	cout<<ans+sum;
	return 0;
}

#一名爱打篮球的oier#

posted @ 2024-03-06 16:36  __kw  阅读(9)  评论(0编辑  收藏  举报