[南海云课堂] [kruskal] [贪心] 走廊泼水节
题意
给定一棵
求增加的边的权值总和最小是多少。
注意: 树中的所有边权均为整数,且新加的所有边权也必须为整数。
思路
主要考察了对
不妨思考怎么加边才能使原最小生成树唯一。
回顾
那么最简单的加边方式就是在同一个连通块内连边,为了保证加边后还是原来的最小生成树,还需使得这些边的边权大于最近一次合并这个连通块的边的边权。
回到
那么新加的边数
至于
代码
好累啊,其实放代码里就两句话的事。
#include<bits/stdc++.h>
using namespace std;
const int N=6e3+5;
int t,n,u,v,w,ans;
int fa[N],siz[N];
struct edge{
int u,v,w;
}e[2*N];
inline int find(int k){
if(fa[k]==k){
return k;
}
return fa[k]=find(fa[k]);
}
inline int get(int k){
return k*(k-1)/2;
}
int main(){
cin>>t;
while(t--){
ans=0;
scanf("%d",&n);
for(int i=1; i<=n;i++){
fa[i]=i;
siz[i]=1;
}
for(int i=1; i<=n-1;i++){
scanf("%d%d%d",&u,&v,&w);
e[i]={u,v,w};
}
sort(e+1,e+n,[](edge a,edge b){return a.w<b.w;});
for(int i=1; i<=n-1;i++){
int u=e[i].u,v=e[i].v,w=e[i].w;
int fu=find(u),fv=find(v);
ans+=(get(siz[fu]+siz[fv])-get(siz[fu])-get(siz[fv])-1)*(w+1); //计算答案
fa[fu]=fv;
siz[fv]+=siz[fu]; //维护 siz
}
printf("%d\n",ans);
}
return 0;
}