[补档计划] 动态规划3 - 树形DP

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[补档计划] 动态规划3 - 树形DP相关的知识,希望对你有一定的参考价值。

  树形DP 是一类 OI 中的问题, 即对一棵树进行 DP .

  很多时候要进行两次 DP , 第一次处理子树内的情况, 第二次处理所有的情况.

  关键靠做题.

 

[CF697D] Puzzles

题意

  给定一棵 $N$ 个节点的树.

  求进行 DFS , 每个节点的时间戳的期望值.

分析 树的遍历 & 特性分析

  进行 DFS , 根的时间戳一定是 1 .

  $f[1] = 1$ .

  $f[next] = f[x] + \sum_{i = 1} ^ c \frac{1}{c} \sum_{son \ne next} size[son] + 1 = f[x] + \frac{1}{2}\sum_{son\ne next}size[son] + 1$ .

实现

技术分享
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>

#define F(i, a, b) for (register int i = (a); i <= (b); i++)
#define fore(k, x) for (register int k = hd[x]; k > 0; k = nx[k])

#define db double

const int N = 100005;

int n, tot, hd[N], nx[N], v[N];
int s[N];
db f[N];

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x * 10 + c - 0; return x * f;
}

inline void Ins(int x, int y) { nx[++tot] = hd[x], hd[x] = tot, v[tot] = y; }
void Siz(int x) {
    s[x] = 1;
    fore(k, x) {
        Siz(v[k]);
        s[x] += s[v[k]];
    }
}

void Solve(int x) {
    long long sum = 0; fore(k, x) sum += s[v[k]];
    fore(k, x) {
        f[v[k]] = f[x] + 1 + (sum - s[v[k]]) / 2.0;
        Solve(v[k]);
    }
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("CF697D.in", "r", stdin);
        freopen("CF697D.out", "w", stdout);
    #endif

    n = rd(); F(i, 2, n) Ins(rd(), i);

    Siz(1);

    f[1] = 1.0;
    Solve(1);
    F(i, 1, n) printf("%0.8lf ", f[i]);
    printf("\n");

    return 0;
}
View Code

 

以上是关于[补档计划] 动态规划3 - 树形DP的主要内容,如果未能解决你的问题,请参考以下文章

动态规划专题——树形DP

信息学奥赛一本通 5.2 树形动态规划

树形 DP 总结

树形 DP 总结

[动态规划][树形dp]Bichrome Tree

ACM - 动态规划小白入门:背包 / 线性 / 区间 / 计数 / 数位统计 / 状压 / 树形 / 记忆化 DP