Description
YJC最近在学习图的有关知识。今天,他遇到了这么一个概念:随机游走。随机游走指每次从相邻的点中随机选一个走过去,重复这样的过程若干次。YJC很聪明,他很快就学会了怎么跑随机游走。为了检验自己是不是欧洲人,他决定选一棵树,每条边边权为1,选一对点s和t,从s开始随机游走,走到t就停下,看看要走多长时间。但是在走了10000000步之后,仍然没有走到t。YJC坚信自己是欧洲人,他认为是因为他选的s和t不好,即从s走到t的期望距离太长了。于是他提出了这么一个问题:给一棵n个点的树,问所有点对(i,j)(1≤i,j≤n)中,从i走到j的期望距离的最大值是多少。YJC发现他不会做了,于是他来问你这个问题的答案。
Solution
之前不是怎么会求期望,做了这题之后会了许多。
我们设f[i]和g[i]分别为i向上走到父亲的期望值和i的父亲向下走到i的期望值。
先来看看f,设y是x的父亲,z是x的其中一个儿子,p是x的度(所以
1p
就是x走到其他点的概率)。那么
f[x]=1p+∑z∈son[x]1p∗(f[x]+f[z]+1)
,因为x可以直接走到y,那么就是
1p∗1=1p
,然后x可以走到其中的一个儿子z,概率为
1p
,步数用了1,然后从z向上走到x的期望是
f[z]
,再从x向上走到y的期望步数是
f[x]
,所以就有上面的式子。
把式子化简一下,就可以变成
1pf[x]=1+1p∑z∈son[x]f[z]
,两边同时乘以
p
,那么
我们再来看看g,假设要走到儿子u。
g[u]=1p+1p∑z∈son[x]且z≠u(f[z]+g[u]+1)+1p(g[u]+g[x]+1)
。因为我们可以直接走到u节点,那么就是
1p∗1=1p
,然后我们可能会走到其他的子节点z,那么概率为
1p
,步数用了1,然后从z到x期望步数为f[z],然后再从x到u期望步数为g[u]。从x还可能往父节点y走,概率为
1p
,步数用了1,从y到x的期望步数为g[x],从x到u的期望步数为g[u]。所以就有上式。
那式子化简一下
g[u]=p+∑z∈son[x]且z≠uf[z]+g[x]
,那么把f[x]给带进去,式子就变成了
g[u]=f[x]+g[x]−f[u]
现在的问题就是怎么求最大值,我们设b[i][0]和b[i][1]分别为i这个节点向下的最大期望步数和从i的子树里面的一个节点向上走到i的最大期望步数。
那么b的转移很显然。
但是有可能b[i][0]和b[i][1]是同一个子节点转移过来的,这样直接加会有问题,所以我们还要设一个c[i][0]和c[i][1]来表示次大的期望步数,如果b的两个值是由相同的节点转移过来的话,那么就把b和c交叉匹配来更新答案。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=100007;
int i,j,k,l,t,n,m;
int first[maxn*2],last[maxn*2],next[maxn*2],num;
int f[maxn],g[maxn],a[maxn],b[maxn][2],c[maxn][2],ans1;
double ans;
void add(int x,int y){last[++num]=y,next[num]=first[x],first[x]=num;}
void dfs(int x,int y){
int i;
f[x]=a[x];
rep(i,x){
if(last[i]!=y){
dfs(last[i],x);
f[x]+=f[last[i]];
}
}
}
void dfs1(int x,int y){
int i;
rep(i,x){
if(last[i]!=y){
g[last[i]]=f[x]+g[x]-f[last[i]];
dfs1(last[i],x);
}
}
}
void dfs2(int x,int y){
int i;int p=0,q=0;
rep(i,x){
if(last[i]!=y){
dfs2(last[i],x);
if(b[last[i]][0]+g[last[i]]>b[x][0]){
c[x][0]=b[x][0];
b[x][0]=b[last[i]][0]+g[last[i]];
p=last[i];
}
else if(b[last[i]][0]+g[last[i]]>c[x][0]){
c[x][0]=b[last[i]][0]+g[last[i]];
}
if(b[last[i]][1]+f[last[i]]>b[x][1]){
c[x][1]=b[x][1];
b[x][1]=b[last[i]][1]+f[last[i]];
q=last[i];
}
else if(b[last[i]][1]+f[last[i]]>c[x][1]){
c[x][1]=b[last[i]][1]+f[last[i]];
}
}
}
if(p!=q)ans1=max(b[x][0]+b[x][1],ans1);
else{
ans1=max(ans1,max(c[x][1]+b[x][0],c[x][0]+b[x][1]));
}
}
int main(){
// freopen("rw.in","r",stdin);
// freopen("rw.out","w",stdout);
freopen("fan.in","r",stdin);
scanf("%d",&n);
fo(i,1,n-1){
scanf("%d%d",&k,&l);
add(k,l),add(l,k);
a[k]++,a[l]++;
}
dfs(1,0);dfs1(1,0);
dfs2(1,0);
ans=ans1;
printf("%.5lf\n",ans);
}