这个题一看就是最小生成树,但是这题关键是确定边权。
首先为了安慰奶牛,一定要遍历每个奶牛并且回到起点,所以每条边会被经过两次,而为了通过这条边必须和两端点奶牛谈话,因此要再加上两端点的c值。综上(i,j)边权为l(i,j) * 2 + c_i + c_j。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define N 10010 #define M 10000000 using namespace std; int n,m; struct qwq { int x,y,val; bool operator < (const qwq &a) const { return val < a.val; } }e[M]; int fa[N],siz[N]; int find(int x) { if(fa[x] != x) fa[x] = find(fa[x]); return fa[x]; } void merge(int x,int y) { if(siz[x] > siz[y]) swap(x,y); siz[y] += siz[x]; fa[x] = y; return; } int kruskal() { sort(e + 1,e + 1 + m); int tot = 0,ans = 0; for(int i = 1;i <= m;i++) { int x = find(e[i].x),y = find(e[i].y); if(x != y) { merge(x,y); ans += e[i].val; tot++; } if(tot == n - 1) break; } return ans; } int c[N]; using namespace std; int main() { scanf("%d %d",&n,&m); int minn = 1000000; for(int i = 1;i <= n;i++) { scanf("%d",&c[i]); minn = min(c[i],minn); fa[i] = i; siz[i] = 1; } for(int i = 1;i <= m;i++) { scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].val); e[i].val = (e[i].val << 1) + c[e[i].x] + c[e[i].y]; } printf("%d ",kruskal() + minn); return 0; }