[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\neq v} { \frac{1}{k}\times (1+val_{son}+dow_v)} + \frac{1}{k}\times (1+dow_{fa}+dow_v)\]

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

化简得:

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

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

\[val_{rt} = \sum_{son} {\frac{1}{k} + \frac{1}{k} \times (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\n",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;
}

原文地址:https://www.cnblogs.com/Chtholly/p/11730108.html

时间: 2024-11-05 14:38:16

[CSP校内集训]tree(期望DP)的相关文章

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

题目 有两条蛇(1号蛇和2号蛇)在n行m列的地图上,地图上有障碍物.一条蛇碰到蛇身/障碍物/边界就会死.蛇身会不断长长--可以理解为蛇尾位置不会变,蛇只会向前伸展不会缩尾巴.两条蛇都绝顶聪明,如果自己能赢,一定会尽量快地赢;如果自己会输,一定会死得尽量晚.给出初始局面,两蛇轮流走,每次可以且必须向上下左右移动一格.1号蛇先走,请告诉我谁会在多少回合时赢.\((n,m\leq 20)\)且\(0\)的数量不超过\(50\) \(\alpha - \beta\)剪枝 AlphaBeta剪枝算法是一个

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

题意 给一个DAG,多次询问,每次给定\(k\)个点,求1到这些点的必经点的交集大小 思路 支配树裸题,建好DAG的支配树后\(k\)个点LCA的深度即为答案 Code #include<bits/stdc++.h> #define N 100005 using namespace std; int n,m,q; int rd[N],f[N][18],dep[N]; struct Edge { int next,to; }edge[N<<1],edge1[N<<1];i

[CSP校内集训]rank

题意 给出一个字符串后缀排序之后的数组\(sa_i\),求原字符串(字典序最小),无解输出-1 思路 显然从\(rk_1\)开始填字符是可以保证字符单调不降的 找到\(sa\)值相邻的两个位置,现在需要知道\(rk_i\)和\(rk_{i+1}\)是否可以填相邻字符:当它们填相同字符时需要比较后一位,如果相对关系相同则可行(因为后一位默认已经成立) 举个栗子:\(4,2,3,1\),查看4能不能和3填同一个字符,则判断后一位2和1:而\(4>3 \&\& 2>1\),所以可以相

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

题意 给\(n\)个互不相交的矩形,再给\(m\)个询问,每次给一个矩形求它与这\(n\)个矩形的面积交 思路 自己写的太丑了导致DEBUG了一个半小时qwq 一对矩形的交可以拆分成二维前缀和形式下的矩形的交,于是变成判断16次矩形的交(不想画图...只想口胡) 这些矩形都有\(x_0=0,y_0=0\),即左下角为坐标原点,于是一个矩形可以只用右上角的坐标表示: 对于一个询问的矩形\((x,y)\)和另一个矩形\((x_i,y_i)\),它们的交为\(min(x,x_i)\times min(

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

题意 给一个边带权的有向图,可以花费边权使得一条边反向:通过翻转边让原图变成一个DAG,要求是所有花费中的最大值最小\(,(n,m\leq 200000)\),保证无重边和自环 解法1 考场上没看出来性质,于是口胡了一个乱搞做法 连好边后直接对原图进行一遍拓扑排序,由于原图不是DAG,所以会有无法入队的环存在:如果当前队列为空而有点没有被遍历到,那么就强行选择一个点将连向它的边翻转: 具体的,我们选择\((max(\) 连向\(i\)的边 \())\)最小的\(i\),由于翻转了连向\(i\)的

Codeforces.280C.Game on Tree(期望)

题目链接 参考:浅谈期望的线性性(可加性) Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望(这个的前半部分分析并没有看..) \(Description\) 给你一棵有\(n\)个白点的有根树,每次随机选择一个点,将它和它的子树中所有点染黑. 问期望操作多少次后所有点都被染黑? \(Solution\) 期望好玄啊..(好吧是我太弱) 因为概率具有可加性,一棵树可以分解为多棵子树,而子树分解的最终状态就是点,所以我们可以计算每个点的期望操作次

「csp校内训练 2019-10-24」解题报告

「csp校内训练 2019-10-24」解题报告 T1.猴猴吃苹果 \(Description\) 猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有 \(N \ (N \leq 50000)\) 个苹果,每个苹果有一个编号,分别为 \(0\) ~ \(N - 1\) 它们之间由 \(N-1\) 个树枝相连,猴猴可以从树枝的一端爬到树枝的另一端,所以猴猴可以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置. 猴猴开始在编号为 \(K \ (K < N)\) 的苹果的位置,并且把这个苹果吃

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

11.7 CSP赛前集训小结

11.7 CSP赛前集训小结 今天是单赛日 1.上午的订正:没啥好说的 昨天的T1,稍微写下思路,维护高度差然后直接分情况讨论会很让人自闭,再加上符号+-和变化量的不同,会爆炸,那么不妨将之间的变化先减去,算上答案后再再加回来即可,正难则反的道理. #include<stdio.h> #include<bits/stdc++.h> #define maxn 200005 using namespace std; long long Ht[maxn]; long long n,q,s