随机游走ah

来源:互联网 发布:谷歌在线翻译软件 编辑:程序博客网 时间:2024/04/28 23:21

题目描述
YJC最近在学习图的有关知识。今天,他遇到了这么一个概念:随机游走。随机游走指每次从相邻的点中随机选一个走过去,重复这样的过程若干次。YJC很聪明,他很快就学会了怎么跑随机游走。为了检验自己是不是欧洲人,他决定选一棵树,每条边边权为1,选一对点s和t,从s开始随机游走,走到t就停下,看看要走多长时间。但是在走了10000000步之后,仍然没有走到t。YJC坚信自己是欧洲人,他认为是因为他选的s和t不好,即从s走到t的期望距离太长了。于是他提出了这么一个问题:给一棵n个点的树,问所有点对(i,j)(1≤i,j≤n)中,从i走到j的期望距离的最大值是多少。YJC发现他不会做了,于是他来问你这个问题的答案。

输入
第一行包含一个整数n,表示点数。
接下来n-1行,第(i+1)行包含两个整数ui和vi,表示树的一条边。
输出
输出一行,包含一个实数,表示最大的期望距离,保留五位小数。

样例输入
3
1 2
2 3
样例输出
4.00000

提示
s=1,t=3,从1走到2距离为1,从2走到3的期望距离d满足d=0.5(d+2)+0.5,解得d=3,所以从1走到3的期望距离为4。
【数据说明】
对于30%的数据,满足n≤5。
对于50%的数据,满足n≤3000。
对于100%的数据,满足n≤100000。

题解:
我们可以把无向边拆成两条无向边,记f[i,j]表示边i→j,i走到j的期望步数。则有这里写图片描述 化简可得
这里写图片描述如果i为叶子节点,则显然f[i,j]=1。所以我们可以自下而上O(n)计算出f[i,fa[i]]——fa[i]为i的父亲。剩下只需计算f[fa[i],i]。通过观察我们可以进一步得到
这里写图片描述
f[i,fa[i]]=2*siz[i]-1;
所以f[fa[i],i]=2*(n-siz[i])-1;
这样我们就得到了所有边的期望步数,接着我们只需树形DP一下,记录子树内一点到根的最大值与根到子树内一点的最大值酒可以转移了。时间复杂度O(n)。

const p=998244353;vartot,i,u,v:longint;n,ans:int64;head,ret,next,size,w,a,b,c,d:array[0..200022] of int64;function max(a,b:int64):int64;begin  if a>b then exit(a) else exit(b);end;procedure ins(u,v:longint);begin  tot:=tot+1;  ret[tot]:=v;  next[tot]:=head[u];  head[u]:=tot;end;procedure dfs(u,pre:longint);vari,v:longint;begin  i:=head[u];  size[u]:=1;  while i<>0 do  begin    v:=ret[i];    if v<>pre then    begin      dfs(v,u);      w[i xor 1]:=2*size[v]-1;      w[i]:=2*n-2-w[i xor 1];      size[u]:=size[u]+size[v];    end;    i:=next[i];  end;end;procedure find(u,pre:longint);vari,j,v:longint;begin   i:=head[u];   while i<>0 do   begin     v:=ret[i];     if v<>pre then     begin       find(v,u);       a[v]:=a[v]+w[i];       a[u]:=max(a[u],a[v]);       b[v]:=b[v]+w[i xor 1];       b[u]:=max(b[u],b[v]);     end;     i:=next[i];   end;   j:=0;   i:=head[u];   while i<>0 do   begin     v:=ret[i];     if v<>pre then     begin       j:=j+1;       c[j]:=b[v];       d[j]:=b[v];     end;     i:=next[i];   end;   for i:=1 to j do     c[i]:=max(c[i],c[i-1]);   d[j+1]:=0;   for i:=j downto 1 do     d[i]:=max(d[i],d[i+1]);   i:=head[u];   j:=0;   while i<>0 do   begin     v:=ret[i];     if v<>pre then     begin       ans:=max(ans,a[v]+max(c[j],d[j+2]));       j:=j+1;     end;     i:=next[i];   end;end;begin  tot:=1;  readln(n);  for i:=1 to n-1 do  begin    readln(u,v);    ins(u,v);    ins(v,u);  end;  dfs(1,-1);  find(1,-1);  write(ans,'.00000');end.
0 0