【题解】
对于一棵树:
先转化成有根树,结点u到"出口"的期望长度为:u的父结点、全部子结点到"出口"的期望长度+u到它们的距离 的平均值
不难想到动态规划:用up[u],down[u]记录u向上,向下到"出口"的期望长度,它们可以递推求得
对于环套树树:
环上的节点很少,在找环后暴力求出环上节点的up值
然后求出所有节点的down值
再然后,求出挂在基环上的子树中根以外所有节点的up值(因为要用到down值,所以放到最后求)
记fa[u],son[u]为u的父、子结点数
那么ans=sigma(fa[u]*up[u]+son[u]*down[u])(fa[u]+son[u])
【代码】
#include<stdio.h>
#include<stdlib.h>
double w[200005]={0},up[100005]={0},down[100005]={0},fa[100005]={0},son[100005]={0},len[25][25]={0};//fa[i],son[i]:i的父/子结点数
int u[200005]={0},v[200005]={0},first[100005]={0},next[200005]={0};
int hash[100005]={0},cir[25]={0},cirE[25]={0},La[25]={0},Ne[25]={0},vis[25]={0};//cir[i]:环上的点号, cirE[i]:环上的边号, La/NE:前驱/后继
int e=0,flag=0,p=0,pE=0;
void tj(int x,int y,double z)
{
u[++e]=x;
v[e]=y;
w[e]=z;
next[e]=first[x];
first[x]=e;
}
void get_cir(int x,int f)
{
int i;
hash[x]=1;
for(i=first[x];i!=0;i=next[i])
if(v[i]!=f)
{
if(hash[v[i]]==1)
{
cirE[++pE]=i;
flag=v[i];
return;
}
get_cir(v[i],x);
if(flag>0)
{
cirE[++pE]=i;
if(flag==x) flag=-1;
return;
}
if(flag==-1) break;
}
hash[x]=0;
}
void get_L_N(int x,int f)//得到环上结点的前驱后继
{
int i;
if(x==1&&vis[x]==1) return;
for(i=first[cir[x]];i!=0;i=next[i])
if(hash[v[i]]!=f&&hash[v[i]]>0&&vis[hash[v[i]]]==0)
{
vis[hash[v[i]]]=1;
Ne[x]=hash[v[i]];
La[hash[v[i]]]=x;
get_L_N(hash[v[i]],x);
}
}
void get_down(int x,int f)
{
int i;
for(i=first[x];i!=0;i=next[i])
if(v[i]!=f&&hash[v[i]]==0)
{
fa[v[i]]=1;
get_down(v[i],x);
son[x]++;
down[x]+=down[v[i]]+w[i];
}
if(son[x]>0) down[x]/=son[x];
}
void get_up(int x,int f,int fE)
{
int i;
up[x]=w[fE];
if(fa[f]+son[f]>1) up[x]+=(fa[f]*up[f]+son[f]*down[f]-w[fE]-down[x])/(fa[f]+son[f]-1);
for(i=first[x];i!=0;i=next[i])
if(v[i]!=f) get_up(v[i],x,i);
}
int main()
{
double z,P,ans=0;
int n,m,i,j,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%lf",&x,&y,&z);
tj(x,y,z);
tj(y,x,z);
}
get_cir(1,0);
if(m<n)//无环
{
get_down(1,0);
for(i=first[1];i!=0;i=next[i])
get_up(v[i],1,i);
}
else//有环
{
for(i=1;i<=n;i++)
if(hash[i]>0)
{
cir[++p]=i;//注意:环上相邻的点编号不一定相邻,在环上的序号也不一定相邻
hash[i]=p;//结点i在环上的序号
fa[i]=2;
}
for(i=1;i<=pE;i++)
len[hash[ u[cirE[i]] ]][hash[ v[cirE[i]] ]]=len[hash[ v[cirE[i]] ]][hash[ u[cirE[i]] ]]=w[cirE[i]];
get_L_N(1,0);
for(i=1;i<=p;i++)
get_down(cir[i],0);
for(i=1;i<=p;i++)
{
for(P=1,j=Ne[i];j!=i;j=Ne[j])//往后找
{
if(Ne[j]!=i) up[cir[i]]+=P*(len[La[j]][j]+down[cir[j]]*son[cir[j]]/(son[cir[j]]+1));
else up[cir[i]]+=P*(len[La[j]][j]+down[cir[j]]);
P/=(son[cir[j]]+1);
}
for(P=1,j=La[i];j!=i;j=La[j])//往前找
{
z=up[cir[i]];
if(La[j]!=i) up[cir[i]]+=P*(len[Ne[j]][j]+down[cir[j]]*son[cir[j]]/(son[cir[j]]+1));
else up[cir[i]]+=P*(len[Ne[j]][j]+down[cir[j]]);
P/=(son[cir[j]]+1);
}
up[cir[i]]/=2;
}
for(i=1;i<=p;i++)
for(j=first[cir[i]];j!=0;j=next[j])
if(hash[v[j]]==0) get_up(v[j],cir[i],j);
}
for(i=1;i<=n;i++)
ans+=(up[i]*fa[i]+down[i]*son[i])/(fa[i]+son[i]);
printf("%.5lf",ans/(double)n);
return 0;
}