題意 抄襲自https://www.cnblogs.com/Paul-Guderian/p/7624039.html 有n個房間,由n-1條隧道連通起來,形成一棵樹,從結點1出發,開始走,在每個結點i都有3種可能(概率之和為1):1.被殺死,回到結點1處(概率為ki)2.找到出口,走出迷宮 (概率為 ...
題意
抄襲自https://www.cnblogs.com/Paul-Guderian/p/7624039.html
有n個房間,由n-1條隧道連通起來,形成一棵樹,從結點1出發,開始走,在每個結點i都有3種可能(概率之和為1):1.被殺死,回到結點1處(概率為ki)2.找到出口,走出迷宮 (概率為ei)
3.和該點相連有m條邊,隨機走一條求:走出迷宮所要走的邊數的期望值。(2≤n≤10000)
Sol
非常nice的一道題。
我簡單的說一下思路:首先列出方程,$f[i]$表示在第$i$個位置走出迷宮的期望步數。
轉移方程分葉子節點和父親節點討論一下,發現都可以化成$f[x] = a f[1] + b f[fa] + c$的形式
然後直接遞推繫數即可
具體可以看https://www.cnblogs.com/Paul-Guderian/p/7624039.html
/* */ #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<set> #include<queue> #include<cmath> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second //#define int long long //#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++) //char buf[(1 << 22)], *p1 = buf, *p2 = buf; using namespace std; const int MAXN = 1e5 + 10, INF = 1e9 + 10; const double eps = 1e-10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N; vector<int> v[MAXN]; double b[MAXN], e[MAXN], A[MAXN], B[MAXN], C[MAXN]; bool dcmp(double x) { if(fabs(x) < eps) return 0; else return 1; } void init() { for(int i = 1; i <= N; i++) v[i].clear(); } double Get(int x) { return (1 - b[x] - e[x]) / (v[x].size()); } bool dfs(int x, int fa) { if(v[x].size() == 1 && (v[x][0] == fa)) {A[x] = b[x], C[x] = B[x] = Get(x); return 1;} double As = 0, Bs = 0, Cs = 0; for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; if(to == fa) continue; if(!dfs(to, x)) return 0; As += A[to]; Bs += B[to]; Cs += C[to] + 1; } double P = Get(x); double D = (1 - Bs * P); if(!dcmp(D)) return 0; A[x] = (b[x] + As * P) / D; B[x] = P / D; C[x] = (Cs * P + ((x == 1) ? 0 : P)) / D; return 1; } int main() { int T = read(); for(int GG = 1; GG <= T; GG++) { N = read(); init(); //printf("%d ", v[3].size()); for(int i = 1; i <= N - 1; i++) { int x = read(), y = read(); v[x].push_back(y); v[y].push_back(x); } for(int i = 1; i <= N; i++) b[i] = (double) read() / 100, e[i] = (double) read() / 100; if(dfs(1, 0) && (dcmp(1 - A[1]))) printf("Case %d: %.10lf\n", GG, C[1] / (1 - A[1])); else printf("Case %d: impossible\n", GG); } return 0; } /* */