CF696B Puzzles
Description
Barney lives in country USC (United States of Charzeh). USC has n cities numbered from 1 through n and n - 1 roads between them. Cities and roads of USC form a rooted tree (Barney’s not sure why it is rooted). Root of the tree is the city number 1. Thus if one will start his journey from city 1, he can visit any city he wants by following roads.
Some girl has stolen Barney’s heart, and Barney wants to find her. He starts looking for in the root of the tree and (since he is Barney Stinson not a random guy), he uses a random DFS to search in the cities. A pseudo code of this algorithm is as follows:
let starting_time be an array of length n current_time = 0 dfs(v): current_time = current_time + 1 starting_time[v] = current_time shuffle children[v] randomly (each permutation with equal possibility) // children[v] is vector of children cities of city v for u in children[v]: dfs(u)As told before, Barney will start his journey in the root of the tree (equivalent to call dfs(1)).
Now Barney needs to pack a backpack and so he wants to know more about his upcoming journey: for every city i, Barney wants to know the expected value of starting_time[i]. He’s a friend of Jon Snow and knows nothing, that’s why he asked for your help.
下面是译文:
Bob和Alice出去度蜜月,但Alice不慎走失,Bob在伤心过后,决定前去寻找Alice。
他们度蜜月的地方是一棵树,共有N个节点,Bob会使用下列DFS算法对该树进行遍历。starting_time是一个容量为n的数组
current_time = 0
dfs(v):
current_time = current_time + 1
starting_time[v] = current_time
将children[v]的顺序随机排列 (每个排列的概率相同)
// children[v]v的直接儿子组成的数组
for u in children[v]:
dfs(u)1是这棵树的根,Bob会从1出发,即运行dfs(1),现在他想知道每个点starting_time的期望值。
终于把这道题搞出来了... 汪汪大哭
真的是一道很好的期望dp题目
将到达每个节点$u$的期望时间戳记为$ans[u]$ 因为他是随机$dfs$所以他的兄弟节点会对他的期望时间戳产生贡献
横向来看 只看该节点与他的兄弟节点 将其父亲的儿子个数记为$m$ 也就是包括他自己的兄弟节点的个数
假设他在当前兄弟的$dfs$序中排名为$i$ 那么其余的每个兄弟节点排在他前面的概率是$\frac{i - 1}{m - 1}$
所以每个兄弟节点$bro$对他产生的贡献为$\frac{i - 1}{m - 1}\cdot size[bro]$
那么总贡献为 $\frac{i - 1}{m - 1}\cdot \sum_{bro \neq u}size[bro]$
将$\sum_{bro \neq u}size[bro]$ 记作$sum$ 易知$sum = size[fa] - size[u] - 1$ 减一是因为减去该子树的根节点
显然 节点$u$排名为$i$的情况的概率为$\frac{1}{m}$
所以$ans[u] = \frac{1}{m}\cdot \sum_{i = 1}^{m}\frac{i - 1}{m - 1}\cdot sum$
化简得 $ans[u] = \frac{1}{2}\cdot sum$
最后$ans[u] += ans[fa] + 1$ 加一是加上前面访问完了之后下一步走到$u$的步数
代码
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int size[N], sum[N], head[N], nex[2 * N], tov[2 * N], n, tot; double ans[N]; void add(int u, int v) { tot ++; nex[tot] = head[u]; tov[tot] = v; head[u] = tot; } void dfs(int u, int fa) { size[u] = 1; for(int i = head[u];i;i = nex[i]) { int v = tov[i]; if(v == fa) continue; dfs(v, u); size[u] += size[v]; } for(int i = head[u];i;i = nex[i]) { int v = tov[i]; if(v == fa) continue; sum[v] = size[u] - size[v] - 1; } } void Add_Edge( ) { scanf("%d",& n); for(int i = 1;i < n;i ++) { int fa; scanf("%d",& fa); add(fa, i + 1); add(i + 1, fa); } dfs(1, 1); } void Dfs(int u, int fa) { for(int i = head[u];i;i = nex[i]) { int v = tov[i]; if(v == fa) continue; ans[v] = ans[u] + 1 + 0.5 * sum[v]; Dfs(v, u); } } int main( ) { Add_Edge( ); ans[1] = 1; Dfs(1, 1); for(int i = 1;i <= n;i ++) printf("%.1lf ", ans[i]); }