Codeforces 696B Puzzles(期望+树形dp)

题意:

对树做dfs的时候,每一个点都有一个时间戳,问你如果每次选择子节点都是等概率的情况下,每个点的期望时间戳是多少。

解法:

一看就是典型的树形dp求期望的题目,我们考虑的是其他的点对某一个点的贡献度,最后的出的转移方程就是dp[v] = dp[u] + 1 + (sz[u] - sz[v] - 1]) * 0.5。
得到这个方程有两个方法,第一种很好理解,首先子节点最起码比父节点要大1,然后考虑这个子节点和其他兄弟节点的关系,其他的兄弟节点要么在他之前访问,要么在这时候访问,概率都是0.5,所以对这个店的贡献就是其他兄弟节点的子树大小乘以0.5;第二种,我们就需要推导一下公式,我就不具体写出来了,大概的思路就是假设当前节点是在所有兄弟节点中第i个被访问的,那么他的期望就是前面i-1个节点的期望再乘以概率计科,虽然对于某一次的期望的式子比较复杂,但是把他们都求和之后,就会发现能够消掉很多东西,最后也就得到了上面的式子。
代码力两次dfs就可以搞定,很简单。

//  Created by  CQU_CST_WuErli
//  Copyright (c) 2016 CQU_CST_WuErli. All rights reserved.
//
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <sstream>
#define CLR(x) memset(x,0,sizeof(x))
#define OFF(x) memset(x,-1,sizeof(x))
#define MEM(x,a) memset((x),(a),sizeof(x))
#define BUG cout << "I am here" << endl
#define lookln(x) cout << #x << "=" << x << endl
#define SI(a) scanf("%d", &a)
#define SII(a,b) scanf("%d%d", &a, &b)
#define SIII(a,b,c) scanf("%d%d%d", &a, &b, &c)
const int INF_INT=0x3f3f3f3f;
const long long INF_LL=0x7f7f7f7f;
const int MOD=1e9+7;
const double eps=1e-10;
const double pi=acos(-1);
typedef long long  ll;
using namespace std;

int n;
vector<int> g[100010];
int sz[100010];
double ans[100010];

void dfs1(int u) {
    sz[u] = 1;
    for (auto& v : g[u]) {
        dfs1(v);
        sz[u] += sz[v];
    }
}

void dfs2(int u) {
    for (auto& v : g[u]) {
        ans[v] = ans[u] + 1 + (double)(sz[u] - sz[v] - 1) / 2.0;
        dfs2(v);
    }
}

int main(int argc, char const *argv[]) {
#ifdef LOCAL
    freopen("C:\\Users\\john\\Desktop\\in.txt","r",stdin);
    // freopen("C:\\Users\\john\\Desktop\\out.txt","w",stdout);
#endif
    while (SI(n) == 1) {
        for (int i = 1; i <= n; i++)
            g[i].clear(), sz[i] = 0, ans[i] = 0;
        for (int i = 2; i <= n; i++) {
            int x; SI(x);
            g[x].push_back(i);
        }
        dfs1(1);
        ans[1] = 1;
        dfs2(1);
        for (int i = 1; i <= n; i++)
            printf("%f\n", ans[i]);
    }
    return 0;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值