LINKc++
一棵树,上面的每一个点都有必定几率成为起点和终点dom
从起点出发,随机游走,并按照下列规则统计count:spa
DFS(x) if x == exit vertex then finish search flag[x] <- TRUE random shuffle the vertices' order in V(x) // here all permutations have equal probability to be chosen for i <- 1 to length[V] do if flag[V[i]] = FALSE then count++; DFS(y); count++;
求count的指望code
首先来证实一个东西:get
对于每一个节点u,若是这个节点是终点,那么他的贡献是
\[ \sum_{(u,v)\in E}siz_v*sump_v \]
\(sump_v\)是子树内每一个节点做为起始节点的几率和it
首先咱们把一个以u为根子树拿出来,对于其中的每个点vio
若是起始节点s在v的子树内,v必定会被通过1次,贡献\(p_s\)class
若是s不在v的子树内,v有\(\frac{1}{2}\)的几率会被通过,贡献\(p_s*2*\frac{1}{2}=p_s\)遍历
不被通过的贡献是\(0\)统计
而后来证为为何有\(\frac{1}{2}\)的几率被通过
从s开始进入每一个子树,要么遍历完,要么停下来
因此能够认为任何一个子树在停下来以前被访问的几率都是\(\frac{1}{2}\)
而后这题作完了。。。泪奔ing
#include<bits/stdc++.h> using namespace std; typedef double db; const int N = 1e5 + 10; int n, siz[N]; vector<int> g[N]; db p[N], q[N], sump = 0, sumq = 0, ans; void dfs(int u, int fa) { siz[u] = 1; for (auto v : g[u]) { if (v == fa) continue; dfs(v, u); siz[u] += siz[v]; p[u] += p[v]; ans += q[u] * siz[v] * p[v]; } ans += q[u] * (n - siz[u]) * (sump - p[u]); } int main() { scanf("%d", &n); for (int i = 1; i < n; i++) { int u, v; scanf("%d %d", &u, &v); g[u].push_back(v); g[v].push_back(u); } for (int i = 1; i <= n; i++) { scanf("%lf %lf", &p[i], &q[i]); sump += p[i], sumq += q[i]; } dfs(1, 0); printf("%.15lf", ans / (sump * sumq)); return 0; }