题意描述
约翰有N个牧场,编号依次为1到N。每个牧场里住着一头奶牛。连接这些牧场的有P条道路,每条道路都是双向的。第j条道路连接的是牧场Sj和Ej,通行需要Lj的时间。两牧场之间最多只有一条道路。约翰打算在保持各牧场连通的情况下去掉尽量多的道路。
约翰知道,在道路被强拆后,奶牛会非常伤心,所以他计划拆除道路之后就去忽悠她们。约翰可以选择从任意一个牧场出发开始他维稳工作。当他走访完所有的奶牛之后,还要回到他的出发地。每次路过牧场i的时候,他必须花Ci的时间和奶牛交谈,即使之前已经做过工作了,也要留下来再谈一次。注意约翰在出发和回去的时候,都要和出发地的奶牛谈一次话。请你计算一下,约翰要拆除哪些道路,才能让忽悠奶牛的时间变得最少?
分析
我们读题可以注意到
- 约翰打算在保持各牧场连通的情况下去掉尽量多的道路。
- 约翰要拆除哪些道路,才能让忽悠奶牛的时间变得最少?
- 从任意一个牧场出发开始他维稳工作
- 当他走访完所有的奶牛之后,还要回到他的出发地。每次路过牧场i的时候,他必须花Ci的时间和奶牛交谈,即使之前已经做过工作了,也要留下来再谈一次。
我们可以得出这是一道最小生成树的裸题
但是这个题有一些不同,就是我们的边权是等于起点的权加上终点的权加上边权*2,为什么呢,可以举一个最简单的例子,假设从a到b还要回到a,显然我们可以得到以上的结论。
代码
#include<bits/stdc++.h>
using namespace std;
struct rep{
int x,y,z;
}edge[100005];
int n,m,ans=0x3f3f3f3f;
int c[100005];
int fa[100005];
bool cmp(rep a,rep b){
return a.z<b.z;
}
int get(int x)
{
if(x==fa[x])
return x;
else return fa[x]=get(fa[x]);//return一定要记得写
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>c[i],ans=min(ans,c[i]); //因为还得返回原来的位置,所以我们对每个牧场的时间取min,意味着,我们从时间最小的位置出发可以获取最小时间
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
edge[i].x=x;
edge[i].y=y;
edge[i].z=c[x]+c[y]+z*2;
}
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++)
{
int px,py;
px=get(edge[i].x);
py=get(edge[i].y);
if(px==py)
continue;
fa[px]=py;
ans+=edge[i].z;
}
cout<<ans;
}