【NOIP2016提高A组集训第14场11.12】随机游走

44 篇文章 0 订阅
30 篇文章 0 订阅

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发现他不会做了,于是他来问你这个问题的答案。

Input

第一行包含一个整数n,表示点数。
接下来n-1行,第(i+1)行包含两个整数ui和vi,表示树的一条边。

Output

输出一行,包含一个实数,表示最大的期望距离,保留五位小数。

Sample Input

3
1 2
2 3

Sample Output

4.00000

Data Constraint

对于30%的数据,满足n≤5。
对于50%的数据,满足n≤3000。
对于100%的数据,满足n≤100000。

Solution

突然想到了一道叫做游走的题,然而我没做过
发现这个东西比较奇怪,所以比赛时直接弃了

设f[i]表示从i到fa[i]的期望步数,fa[i]为i的父亲,d[i]为i的度数

f[i]=1+(jif[j]+f[i]+1d[i]

就是走到某个儿子再走回来
f[i]=d[i]+(jif[j])d[i]+(d[i]1)f[i]d[i])

把最右边的移项到左边,再化简
f[i]=d[i]+(jif[j])

再设g[i]为从fa[i]到i的期望步数,设k为i的父亲

g[i]=1+g[k]+g[i]+1+(jijif[j]+g[i]+1)d[k]

从父亲走到它的父亲走回来或走到其它儿子再走回来
g[i]=d[i]+(d[i]1)g[i]+g[k]+(jijif[j])d[k]

和上面类似的化简,到最后
g[i]=g[k]+d[k]+(jijif[j])

这样就可以求出两点之间的距离了
每次枚举lca取MAX作为答案

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 101000
#define db double
using namespace std; 
int next[N*10],to[N*10],last[N],tot=0,n,m,d[N],fa[N],f[N],g[N],mx[N],ma[N],ans;
void putin(int x,int y)
{
    next[++tot]=last[x];last[x]=tot;to[tot]=y;
}
void dg(int x,int z)
{
    int bz=1;
    for(int i=last[x];i;i=next[i])
        if(to[i]!=z) fa[to[i]]=x,dg(to[i],x),f[x]+=f[to[i]],bz=0;
    f[x]+=d[x];
}
void dg2(int x,int z)
{
    int jy=0;
    for(int i=last[x];i;i=next[i]) if(to[i]!=z) jy+=f[to[i]];
    for(int i=last[x];i;i=next[i])
        if(to[i]!=z) g[to[i]]=g[x]+d[x]+jy-f[to[i]],dg2(to[i],x);
}
void dfs(int x,int z)
{
    int cmx=0,cma=0,mx1,mx2,ma1,ma2;
    for(int i=last[x];i;i=next[i])
    if(to[i]!=z)
    {
        int y=to[i];
        dfs(y,x);
        int jy=mx[y]+f[y];
        if(jy>mx[x]) cmx=mx[x],mx2=mx1,mx[x]=jy,mx1=y;
        else if(jy>cmx) cmx=jy,mx2=y;
        jy=ma[y]+g[y];
        if(jy>ma[x]) cma=ma[x],ma2=ma1,ma[x]=jy,ma1=y;
        else if(jy>cma) cma=jy,ma2=y;
    }
    if(mx1==ma1) ans=max(ans,max(mx[x]+cma,ma[x]+cmx));
    else ans=max(ans,mx[x]+ma[x]);
}
int main()
{
    freopen("rw.in","r",stdin);freopen("rw.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n-1)
    {
        int x,y;scanf("%d%d",&x,&y);
        putin(x,y);putin(y,x);d[y]++;d[x]++;
    }
    dg(1,0);
    dg2(1,0);
    dfs(1,0);
    printf("%d.00000",ans);
    return 0;
    fclose(stdin);fclose(stdout);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值