题意:先求最小生成树,然后问你在这个最小生成树中任选两个点,问这两个点之间距离的期望。
期望:2*(任意两点之间的距离和)/(n*(n-1))
分析:现在关键是求任意两点之间的距离和。我们可以考虑,最小生成树的每一条边对其的贡献,即:u->v
v的子节点为cnt个(包括它),那么u即u之上的点数为n-cnt。那么根据排列组合,这条边会用到cnt*(n-cnt)次。
dfs一次就可以了。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
#define MAXN 200005
#define LL long long
#define eps 1e-7
struct node
{
LL st,en;
double len;
node(LL st=0,LL en=0,double len=0.0)
:st(st),en(en),len(len){}
};
struct node E[MAXN*10];
LL fa[MAXN];
LL findfa(LL x)
{
if(x==fa[x])return x;
return fa[x]=findfa(fa[x]);
}
bool cmp(node x,node y)
{
return (x.len-y.len)<eps?true:false;
}
struct edge
{
LL en,next;
double len;
}Edge[MAXN*10];
LL p[MAXN],num;
double ans2=0;
void add(LL st,LL en,double len)
{
Edge[num].en=en;
Edge[num].next=p[st];
Edge[num].len=len;
p[st]=num++;
}
void init()
{
memset(p,-1,sizeof(p));
num=0;
}
LL vis[MAXN];
LL cnt[MAXN];
void dfs(LL id,LL n)
{
cnt[id]=1;
vis[id]=1;
for(LL i=p[id];i!=-1;i=Edge[i].next)
{
LL en=Edge[i].en;
double len=Edge[i].len;
if(!vis[en])
{
dfs(en,n);
cnt[id]+=cnt[en];
LL temp=cnt[en]*(n-cnt[en]);
ans2+=(double)temp*len;
}
}
}
int main()
{
LL i,n,m;
LL t;
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%lld%lld%lf",&E[i].st,&E[i].en,&E[i].len);
}
sort(E+1,E+1+m,cmp);
for(i=1;i<=n;i++)
fa[i]=i;
double ans1=0;
ans2=0;
init();
LL id;
for(i=1;i<=m;i++)
{
LL tx=findfa(E[i].st);
LL ty=findfa(E[i].en);
if(tx!=ty)
{
fa[tx]=ty;
ans1+=E[i].len;
add(E[i].st,E[i].en,E[i].len);
add(E[i].en,E[i].st,E[i].len);
id=E[i].st;
}
}
memset(cnt,0,sizeof(cnt));
memset(vis,0,sizeof(vis));
dfs(id,n);
double tt=(double)n*(double)(n-1);
double y=tt/2.0;
ans2=ans2/y;
printf("%.0lf %.2lf\n",ans1,ans2);
}
return 0;
}