Codeforces123E. Maze【樹形dp】【機率dp】【證實題】

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;
}
相關文章
相關標籤/搜索