题目链接
题解
神题啊。。。orz
不过网上题解好难看,数学推导不写\(Latex\)怎么看。。【Latex中毒晚期】
我们由题当然能很快写出\(dp\)方程
设\(f[i]\)表示从\(u\)出发逃离的期望步数,\(m\)为该点度数
然后就会发现这个方程似乎有后效性,立即想高斯消元
一看范围\(n \le 10^4\)什么鬼嘛QAQ。。。
题解是这么说的:
我们设
对于叶子节点,显然有
对于非叶节点,我们展开\(f[v]\)
我们整理一下:
故
然后由于
当\(1 - A_1 = 0\)时无解
否则我们能直接计算出\(f[1]\),即为所求
是不是很神奇?
这个式子的推导主要是利用了式子中有\(f[fa[u]]\)这一项,从而可以从儿子中递推出父亲的信息
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define eps 1e-10
using namespace std;
const int maxn = 10005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,h[maxn],ne,de[maxn],fa[maxn];
struct EDGE{int to,nxt;}ed[maxn << 1];
void build(int u,int v){
ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
de[u]++; de[v]++;
}
double A[maxn],B[maxn],C[maxn],K[maxn],E[maxn];
int dfs(int u){
if (de[u] == 1 && u != 1){
A[u] = K[u];
B[u] = C[u] = 1 - K[u] - E[u];
return true;
}
double m = de[u],tmp = 0;
A[u] = K[u];
B[u] = (1 - K[u] - E[u]) / m;
C[u] = 1 - K[u] - E[u];
Redge(u) if ((to = ed[k].to) != fa[u]){
fa[to] = u; if (!dfs(to)) return false;
A[u] += A[to] * B[u];
C[u] += C[to] * B[u];
tmp += B[to] * B[u];
}
if (fabs(1 - tmp) < eps) return false;
A[u] /= (1 - tmp); B[u] /= (1 - tmp); C[u] /= (1 - tmp);
return true;
}
int main(){
int T = read();
for (int t = 1; t <= T; t++){
n = read(); cls(de); cls(h); ne = 1;
for (int i = 1; i < n; i++) build(read(),read());
for (int i = 1; i <= n; i++) K[i] = read() / 100.0,E[i] = read() / 100.0;
printf("Case %d: ",t);
if (!dfs(1) || fabs(A[1] - 1) < eps) puts("impossible");
else printf("%.10lf\n",C[1] / (1 - A[1]));
}
return 0;
}