[bzoj1232]安慰奶牛
先考虑边的代价,容易发现每一条边都需要走两次,也就是2*边权
再考虑点的代价,由于上面的结论,那么就是度数*点权
然后就可以构造新的边权为2*原边权+连接点的点权,然后求最小生成树即可
注意根还有一个点权,所以再加上根(也就是最小点)的点权即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 10005 4 struct ji{ 5 int x,y,z; 6 }e[N*10]; 7 int n,m,ans,a[N],f[N]; 8 bool cmp(ji x,ji y){ 9 return x.z<y.z; 10 } 11 int find(int k){ 12 if (k==f[k])return k; 13 return f[k]=find(f[k]); 14 } 15 int main(){ 16 scanf("%d%d",&n,&m); 17 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 18 ans=a[1]; 19 for(int i=2;i<=n;i++)ans=min(ans,a[i]); 20 for(int i=1;i<=m;i++){ 21 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); 22 e[i].z=2*e[i].z+a[e[i].x]+a[e[i].y]; 23 } 24 sort(e+1,e+m+1,cmp); 25 for(int i=1;i<=n;i++)f[i]=i; 26 for(int i=1;i<=m;i++) 27 if (find(e[i].x)!=find(e[i].y)){ 28 f[find(e[i].x)]=find(e[i].y); 29 ans+=e[i].z; 30 } 31 printf("%d",ans); 32 }