这题先求出最小生成树,然后在最小生成树中求任意两个点之和的平均数。。因为最小生成树是唯一的,所以期望也就只有一个。求最小生成树的时候把树存起来。求任意两点之和的时候我们求出一条边在求和的时候用了多少次,也就是求该边的左右端点有多少个比如一条边左右两边有A,B个端点,那么利用的次数也就是A*B。
我们可以用dfs来实现,用sum数组表示k点子树上的点(包括他自己),那么kf父亲那边的点就是n-sum[k]。最后载除一个n*(n-1)/2就可得到答案。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
const int N=100005;
const int maxn=1001000;
struct node
{
int v;
__int64 len;
};
vector<node>G[2*N];
struct Node
{
int u,v;
__int64 w;
};
int tol;
Node edge[2*maxn];
void addedge(int u,int v,__int64 w)
{
edge[tol].u=u;
edge[tol].v=v;
edge[tol++].w=w;
}
double dp;
__int64 sum[N];
int f[N];
__int64 n;
int m;
bool cmp(Node a,Node b)
{
return a.w<b.w;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
__int64 kulasal()
{
__int64 ans=0;
for(int i=1;i<=n;i++)
f[i]=i;
int cnt=0;
sort(edge,edge+tol,cmp);
for(int i=0;i<tol;i++)
{
int u=edge[i].u;
int v=edge[i].v;
int w=edge[i].w;
int fx=find(u);
int fy=find(v);
if(fx!=fy)
{
f[fx]=fy;
ans+=w;
node p1,p2;
p1.v=u;
p1.len=w;
p2.v=v;
p2.len=w;
G[u].push_back(p2);
G[v].push_back(p1);
cnt++;
}
if(cnt==n-1)
break;
}
return ans;
}
void dfs(int root,int father)
{
sum[root]=1;
for(int i=0;i<G[root].size();i++)
{
int son=G[root][i].v;
int len=G[root][i].len;
if(son==father)
continue;
dfs(son,root);
sum[root]+=sum[son];
dp+=(sum[son]*(n-sum[son]))*(double)len;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
tol=0;
for(int i=1;i<=n;i++)
G[i].clear();
scanf("%I64d %d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d %d %64d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
__int64 S=kulasal();
memset(sum,0,sizeof(sum));
dp=0;
dfs(1,-1);
__int64 s=n*(n-1)/2;
double ans=dp/(double)s;
printf("%I64d %0.2f
",S,ans);
}
return 0;
}