一开始想生成最小生成树后树DP的,后来发现只要统计每条边对答案的贡献就好了。
每条边的贡献是两边节点数相乘
最后用这个值乘2再除以n(n+1)就可以得到结果
#include<cstdio> #include<string> #include<cstring> #include<algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; struct line { int s,t; double x; int next; bool operator <(line y) const { return x<y.x; } }a[200001],x[1000001]; int head[100001]; int edge; inline void add(int s,int t,double x) { a[edge].next=head[s]; head[s]=edge; a[edge].s=s; a[edge].t=t; a[edge].x=x; } int fa[100001]; double son[100001]; inline int find(int x) { if(x!=fa[x]) fa[x]=find(fa[x]); return fa[x]; } inline void dfs(int d) { son[d]=0; int i; for(i=head[d];i!=0;i=a[i].next) { int t=a[i].t; if(fa[d]!=t) { fa[t]=d; dfs(t); son[d]+=son[t]+1; } } } int main() { int T; scanf("%d",&T); while(T>0) { T--; int n,m; scanf("%d%d",&n,&m); int i; for(i=1;i<=m;i++) scanf("%d%d%lf",&x[i].s,&x[i].t,&x[i].x); sort(x+1,x+1+m); edge=0; memset(head,0,sizeof(head)); for(i=1;i<=n;i++) fa[i]=i; double sx=0; int ss=0; for(i=1;i<=m;i++) { int fx=find(x[i].s),fy=find(x[i].t); if(fx!=fy) { ss++; fa[fx]=fy; edge++; add(x[i].s,x[i].t,x[i].x); edge++; add(x[i].t,x[i].s,x[i].x); sx+=x[i].x; if(ss==n-1) break; } } memset(fa,0,sizeof(fa)); dfs(1); double sum=0; for(i=1;i<=edge;i++) { int s=a[i].s,t=a[i].t; if(fa[s]==t) sum+=a[i].x*(double)(son[1]-son[s])*(double)(son[s]+1); } printf("%.0f %.2f\n",sx,sum*2.0/(double)(n)/(double)(n-1)); } return 0; }