题目:
题解:
感觉相当的复杂。我们先考虑一棵树的情况
首先一个点可以往上走(父节点),可以往下走(子节点),我们就分为这两种情况讨论
一遍dfs可以求出
down[i]=(∑down[j]+len(i,j))/du[i]
d
o
w
n
[
i
]
=
(
∑
d
o
w
n
[
j
]
+
l
e
n
(
i
,
j
)
)
/
d
u
[
i
]
,i为j的父节点
再来一遍dfs求出向上的期望值
up[j]=(down[i]−len(i,j)−down[j])/(du[i]−1)+len(i,j)
u
p
[
j
]
=
(
d
o
w
n
[
i
]
−
l
e
n
(
i
,
j
)
−
d
o
w
n
[
j
]
)
/
(
d
u
[
i
]
−
1
)
+
l
e
n
(
i
,
j
)
,i为j的父节点
但是有环的情况就要特别讨论了
首先这个环导致树变成了len个小树+一个大环,所以我们对所有的小树求down,up比较麻烦,我们先对环上的点求出g[i]表示从这个点开始走的期望,因为环的大小很小,我们枚举root,然后dp,g[i]=(g[v[i]]+len(i,v[i]))/(du[x]+1),算完之后,我们再把down计入贡献直接加权。
算完g和down对答案的贡献之后,我们把环上的du+2,因为环上的两个出边没有算,然后枚举环上每个点,进行up的计算
对于度数为0的情况,要强制置1
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=100005;
int tot,nxt[N*2],point[N],v[N*2],c[N*2],vis[N],du[N],root,num,fa[N],fff;double g[N],f[N],d[N],xin[N];
bool cir[N];
void addline(int x,int y,int z)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;
}
void dfs1(int x)
{
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
if (!vis[v[i]] && !cir[v[i]])
dfs1(v[i]),du[x]++,d[x]+=f[v[i]]+c[i];
if (du[x]) f[x]=d[x]/(double)du[x];
if (x!=root) du[x]++;
}
void dfs2(int x)
{
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
if (!vis[v[i]] && !cir[v[i]]) d[v[i]]+=(d[x]-f[v[i]]-c[i])/(double)max(1,du[x]-1)+c[i],dfs2(v[i]);
}
void dfs3(int x)
{
vis[x]=++num;int j;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa[x])
{
if (!vis[v[i]]) fa[v[i]]=x,dfs3(v[i]);
else if (vis[v[i]]<vis[x])
{
for (cir[v[i]]=1,j=x;j!=v[i];j=fa[j])
cir[j]=1;
}
}
}
void dfs4(int x,int fa)
{
g[x]=0;int fff=1;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa && cir[v[i]] && v[i]!=root) fff=0,dfs4(v[i],x),g[x]+=g[v[i]]+c[i];
if (x==root) return;
int k=du[x];
if (fff) g[x]=d[x]/(double)max(1,du[x]);
else g[x]=(g[x]+d[x])/(double)(du[x]+1);
}
int main()
{
int n,m;scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
addline(x,y,z);
}
double ans=0;root=1;
if (m==n-1) dfs1(1),memset(vis,0,sizeof(vis)),dfs2(1);
else
{
dfs3(1);memset(vis,0,sizeof(vis));
for (int i=1;i<=n;i++) if (cir[i]) root=i,dfs1(i);
for (int i=1;i<=n;i++) if (cir[i]) root=i,dfs4(i,0),xin[i]=g[i];
memset(vis,0,sizeof(vis));
for (int i=1;i<=n;i++) if (cir[i]) du[i]+=2,d[i]+=xin[i];
for (int i=1;i<=n;i++) if (cir[i]) root=i,dfs2(i);
}
for (int i=1;i<=n;i++) ans+=d[i]/(double)du[i];
printf("%.5lf",ans/(double)n);
}