传送门
题意:给一棵nnn个点的带边权树或基环树,随机选一个点作为起点,每次随机走到一个相邻未走过的位置,直到无路可走。求期望路径长度。
n≤105n \leq 10^5n≤105,为基环树时环的大小不超过202020
先考虑树怎么做废话
先只考虑从根往下走
显然就是
fu=∑v∈son(u)w(u,v)+f(v)∣son(u)∣f_u={\sum_{v\in son(u)}w(u,v)+f(v) \over|son(u)|}fu=∣son(u)∣∑v∈son(u)w(u,v)+f(v)
考虑其他位置
再考虑强制第一步往上走,然后强行不走回来的期望为ggg
方程见代码
对于基环树,fff不受影响。
对于环上的点两个方向带着走到这里的概率和距离转一圈,算出ggg,树上点方程不变。
然后就可以了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 100005
#define MAXM 200005
using namespace std;
struct edge{int u,v,w;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
void addnode(int u,int v,int w)
{e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt;
}
int n,m,son[MAXN];
double F[MAXN],G[MAXN];
namespace Tree
{void dfs(int u,int f){for (int i=head[u];i;i=nxt[i])if (e[i].v!=f){++son[u];dfs(e[i].v,u);F[u]+=F[e[i].v]+e[i].w;}if (son[u]) F[u]/=son[u];}void DFS(int v,int f){int u=e[f].u;G[v]=e[f].w+((u==1&&son[u]==1)? 0:((G[u]+F[u]*son[u]-F[v]-e[f].w)/(son[u]-(u==1))));for (int i=head[v];i;i=nxt[i])if (e[i].v!=u)DFS(e[i].v,i);}void solve(){dfs(1,0);for (int i=head[1];i;i=nxt[i]) DFS(e[i].v,i);double ans=F[1];for (int i=2;i<=n;i++) ans+=G[i]/(son[i]+1)+F[i]*son[i]/(son[i]+1);printf("%.5f",ans/n);}
}
namespace Circle
{bool vis[MAXN],isrt[MAXN];int rt[MAXN],w[MAXN],tot,tmp;void findroot(int u,int f){vis[u]=true;for (int i=head[u];i;i=nxt[i])if (!vis[e[i].v]&&e[i].v!=rt[1]){findroot(e[i].v,u);if (isrt[e[i].v]&&e[i].v!=tmp) isrt[rt[++tot]=u]=true,w[tot]=e[i].w;}elseif (e[i].v!=f&&e[i].v!=rt[1])isrt[rt[tot=1]=u]=true,w[1]=e[i].w,tmp=e[i].v;vis[u]=false;}void DFS(int v,int f){int u=e[f].u;if (isrt[u]) G[v]=e[f].w+2.0/(son[u]+1)*G[u]+(F[u]*son[u]-F[v]-e[f].w)/(son[u]+1);else G[v]=e[f].w+(G[u]+F[u]*son[u]-F[v]-e[f].w)/son[u];for (int i=head[v];i;i=nxt[i])if (e[i].v!=u)DFS(e[i].v,i);}void solve(){findroot(1,0);for (int t=1;t<=tot;t++){int u=rt[t];for (int i=head[u];i;i=nxt[i])if (!isrt[e[i].v])++son[u],Tree::dfs(e[i].v,u),F[u]+=F[e[i].v]+e[i].w;if (son[u]) F[u]/=son[u];}for (int i=1;i<=tot;i++){double p=0.5;int dis=0;for (int j=i%tot+1;j!=i;j=j%tot+1){dis+=w[j];if (j%tot+1==i) G[rt[i]]+=p*(dis+F[rt[j]]);else G[rt[i]]+=p*son[rt[j]]/(son[rt[j]]+1)*(dis+F[rt[j]]);p*=1.0/(son[rt[j]]+1);}p=0.5,dis=w[i];for (int j=(i==1? tot:i-1);j!=i;j=(j==1? tot:j-1)){if (i%tot+1==j) G[rt[i]]+=p*(dis+F[rt[j]]);else G[rt[i]]+=p*son[rt[j]]/(son[rt[j]]+1)*(dis+F[rt[j]]);p*=1.0/(son[rt[j]]+1);dis+=w[j];}}for (int t=1;t<=tot;t++){int u=rt[t];for (int i=head[u];i;i=nxt[i])if (!isrt[e[i].v])DFS(e[i].v,i);}double ans=0;for (int i=1;i<=n;i++) ans+=(isrt[i]+1)*G[i]/(son[i]+isrt[i]+1)+F[i]*son[i]/(son[i]+isrt[i]+1);printf("%.5f",ans/n); }
}
int main()
{n=read(),m=read();for (int i=1;i<=m;i++){int u,v,w;u=read(),v=read(),w=read();addnode(u,v,w);addnode(v,u,w);}if (m==n-1) Tree::solve();else Circle::solve();return 0;
}