Codeforces Round #362 (Div. 2) Problem D——Puzzles

题意
遍历一张图,每个节点的子节点排列方式随机等可能,求每个节点访问到的时间的期望
思路
假设四个子节点为A,B,C,D,因为排列等可能,所以A在B前面的概率跟A在B后面的概率相等,C和D对于A而言一样。所以遍历A的时间期望就是( t(B) + t(C) + t(D) )/2 + P。其中t(B)是访问B节点及其子树所需时间,尽管是随机排列,但是B子树中的节点树是确定的,所以t(B)可以确定,P是A的父节点访问时间的期望
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 100005;

struct Edge{
    int u, v, next;
}edge[maxn];

int tot;int first[maxn];
int parent[maxn];
int sub[maxn];
double ans[maxn];

void add(int uu,int vv)
{
    edge[tot].u = uu;
    edge[tot].v = vv;
    edge[tot].next = first[uu];
    first[uu] = tot++;
}

void dfs(int u)
{
    for(int e = first[u]; e != -1; e = edge[e].next){
        dfs(edge[e].v);
        sub[u] += sub[edge[e].v];
    }
    sub[u] += 1;
}

void solve(int u){
    for(int e = first[u]; e != -1; e = edge[e].next){
        int &v = edge[e].v;
        ans[v] = ans[u] + ((double)(sub[u] - sub[v] - 1) / 2) + 1;
        solve(v);
    }
}

int main()
{
//    freopen("data.txt","r",stdin);
    memset(first, -1, sizeof(first));
    memset(sub, 0, sizeof(sub));
    int n;
    scanf("%d",&n);
    for(int i = 2; i <= n; ++i){
        scanf("%d",&parent[i]);
        add(parent[i], i);
    }
    ans[1] = 1;
    dfs(1);
//    for(int i = 1; i <=n; ++i){
//        cout<<sub[i]<<' ';
//    }cout <<endl;
    solve(1);
    printf("%lf",ans[1]);
    for(int i = 2; i <=n; ++i){
        printf(" %lf", ans[i]);
    }
    puts("");
    return 0;
}

sub记录子树中节点总数

发布了267 篇原创文章 · 获赞 12 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/u010734277/article/details/51957484