[CSP校内集训]tree(期望DP)

Posted chtholly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP校内集训]tree(期望DP)相关的知识,希望对你有一定的参考价值。

题意

给一颗树,从1节点出发,走每条边的概率相同且耗时为1,求每个点第一次被遍历到的期望时间((t_1=1)

思路

在树上只有两种移动方式:从儿子到父亲,从父亲到儿子

假设从(rt)走到(v)的期望代价为(dow_i),从(i)走到(rt)的期望代价为(val_i)

假设从(rt)转移到(v)(rt)的度数为(k)(rt)的父亲为(fa),则:

[dow_v = frac{1}{k} + sum_{son}^{son eq v} { frac{1}{k} imes (1+val_{son}+dow_v)} + frac{1}{k} imes (1+dow_{fa}+dow_v)]

意思是:要么从(rt)(v)一步到位,要么有(frac{1}{k})的概率走其他点再走回来重新计算期望

化简得:

[ dow_v = k + sum_{son}^{son eq v} {val_{son} + dow_{fa}}]

这里还有个(val)不知道,所以要先计算它:

[val_{rt} = sum_{son} {frac{1}{k} + frac{1}{k} imes (1+val_{son}+val_{rt})}]

意思是:要么从(v)(rt)一步到位,要么走一步到儿子走回来在重新计算期望

化简得:

[val_{rt} = k + sum_{son} {val_{son}}]

一遍(dfs)自底向上求(val),再一遍(dfs)从上到下求(dow),一个点的答案即为(dow)的前缀和

Code

#include<bits/stdc++.h>
#define N 100005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int n,rd[N],ok=1;
double val[N],dow[N],f[N];

struct Edge
{
    int next,to;
}edge[N<<1];int head[N],cnt=1;
void add_edge(int from,int to)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    head[from]=cnt;
}

template <class T>
void read(T &x)
{
    char c; int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void dfs1(int rt,int fa)
{
    val[rt]=rd[rt];
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        dfs1(v,rt);
        val[rt]+=val[v];
    }
}
void dfs(int rt,int fa)
{
    double sumval=0;
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        sumval+=val[v];
    }
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        f[v]=f[rt]+rd[rt]+dow[rt]+sumval-val[v];
        dow[v]=f[v]-f[rt];
        dfs(v,rt);
    }
}
void solve()
{
    dfs1(1,0);
    f[1]=1.0; dow[1]=0;
    dfs(1,0);
    for(int i=1;i<=n;++i) printf("%.3lf
",f[i]);
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    read(n);
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x);read(y);
        add_edge(x,y);
        add_edge(y,x);
        ++rd[x];++rd[y];
    }
    solve();
    return 0;
}

以上是关于[CSP校内集训]tree(期望DP)的主要内容,如果未能解决你的问题,请参考以下文章

[CSP校内集训]attack(DAG支配树)

[CSP校内集训]pestc(拓扑排序)

[CSP校内集训]矩形面积交(树状数组)

[CSP校内集训]贪吃蛇(阿尔法-贝塔剪枝)

[CSP-S模拟测试]:tree(DP)

校内模拟赛 虫洞(by NiroBC)