http://acm.hdu.edu.cn/showproblem.php?pid=5723
大意是先用最小生成树把路联通,在求出所有点的距离,
最小生成树+求任意两点距离的期望。
最小生成树就不讲了。求期望可以先求出每个边的贡献度,这条边的上下所有点数相乘就是这条边要经过几次,再乘上边长就是这个边的贡献度。
#include<algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define N 100010
struct Node
{
int u,v,w;
Node() {}
Node(int _u,int _v,int _w):u(_u),v(_v),w(_w) {}
};
struct Edge
{
int v,w;
Egde(){}
Edge(int _v,int _w):v(_v),w(_w) {}
};
vector<Node>node;
vector<Edge>edge[N];
int n,m,pre[N];
double dp[N];
int sum[N];
bool cmp(const Node &x,const Node &y)
{
return x.w<y.w;
}
int Find(int a)
{
if(a==pre[a])
{
return a;
}
return pre[a]=Find(pre[a]);
}
long long Kruskal()
{
sort(node.begin(),node.end(),cmp);
for(int i=1; i<=n; i++)
{
pre[i]=i;
}
long long ans=0;
for(int i=0,u,v; i<(int)node.size(); i++)
{
u=node[i].u,v=node[i].v;
u=Find(u),v=Find(v);
if(u==v)
{
continue;
}
pre[u]=v;
ans+=(long long)node[i].w;
edge[node[i].v].push_back(Edge(node[i].u,node[i].w));
edge[node[i].u].push_back(Edge(node[i].v,node[i].w));
}
return ans;
}
void dfs(int root,int father)
{
sum[root]=1;
for(int i=0; i<(int)edge[root].size(); i++)
{
int son=edge[root][i].v;
if(son==father)
{
continue;
}
dfs(son,root);
sum[root]+=sum[son];
dp[root]+=dp[son]+((double)(n-sum[son])*sum[son])*edge[root][i].w;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
node.clear();
for(int i=0,a,b,c; i<m; i++)
{
scanf("%d%d%d",&a,&b,&c);
node.push_back(Node(a,b,c));
}
for(int i=0; i<=n; i++)
{
edge[i].clear();
}
long long ans=Kruskal();
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
dfs(1,0);
double ANS=dp[1];
ANS=ANS/n;
ANS=ANS/(n-1)*2;
printf("%lld ",ans);
printf("%.2lf\n",ANS);
}
return 0;
}