分析:
令
f
u
f_u
fu表示在点
u
u
u时期望需要经过多少条边才能逃出,记
s
o
n
u
son_u
sonu为点
u
u
u的儿子的集合,
f
a
u
fa_u
fau为
u
u
u的父亲,
d
u
d_u
du为点
u
u
u的度,那么显然有:
f
u
=
k
u
f
1
+
(
1
−
k
u
−
e
u
)
(
(
∑
v
∈
s
o
n
u
f
v
+
f
f
a
u
)
/
d
u
+
1
)
(1)
\tag1 f_u = k_uf_1 + (1 - k_u - e_u)((\sum_{v \,\in\, son_u}f_v + f_{fa_u}) / d_u + 1)
fu=kuf1+(1−ku−eu)((v∈sonu∑fv+ffau)/du+1)(1)
经典套路,设:
f
u
=
a
u
f
1
+
b
u
f
f
a
u
+
c
u
(2)
\tag2 f_u = a_uf_1 + b_uf_{fa_u} + c_u
fu=auf1+buffau+cu(2)
将
(
2
)
将(2)
将(2)式带入
(
1
)
(1)
(1)式,得:
f
u
=
k
u
f
1
+
(
1
−
k
u
−
e
u
)
(
∑
v
∈
s
o
n
u
(
a
v
f
1
+
b
v
f
u
+
c
v
)
+
f
f
a
u
)
/
d
u
+
(
1
−
k
u
−
e
u
)
f_u = k_uf_1 + (1 - k_u - e_u)(\sum_{v\,\in\, son_u}(a_vf_1 + b_vf_u + c_v) + f_{fa_u}) / d_u + (1 - k_u - e_u)
fu=kuf1+(1−ku−eu)(v∈sonu∑(avf1+bvfu+cv)+ffau)/du+(1−ku−eu)
令
t
=
(
1
−
k
u
−
e
u
)
/
d
u
,
S
a
=
∑
v
∈
s
o
n
u
a
v
t = (1 - k_u - e_u) / d_u,Sa = \sum_{v\,\in\,son_u}a_v
t=(1−ku−eu)/du,Sa=∑v∈sonuav,
S
b
,
S
c
Sb,Sc
Sb,Sc以此类推,整理一下,得:
f
u
=
(
k
u
+
t
S
a
)
f
1
+
t
f
f
a
u
+
t
S
c
+
t
d
u
1
−
t
S
b
f_u = \frac{(k_u + tSa)f_1 + tf_{fa_u} + tSc + td_u}{1 - tSb}
fu=1−tSb(ku+tSa)f1+tffau+tSc+tdu
即:
a
u
=
k
u
+
t
S
a
1
−
t
S
b
,
b
u
=
t
1
−
t
S
b
,
c
u
=
t
S
c
+
t
d
u
1
−
t
S
b
a_u = \frac{k_u + tSa}{1 - tSb},b_u = \frac{t}{1 - tSb},c_u = \frac{tSc + t d_u}{1 - tSb}
au=1−tSbku+tSa,bu=1−tSbt,cu=1−tSbtSc+tdu
特别地,对于叶子节点,有
S
a
=
S
b
=
S
c
=
0
,
d
u
=
1
Sa = Sb = Sc = 0,d_u = 1
Sa=Sb=Sc=0,du=1。带入式子显然有:
t
=
1
−
k
u
−
e
u
,
a
u
=
k
u
,
b
u
=
1
−
k
u
−
e
u
,
c
u
=
1
−
k
u
−
e
u
t = 1 - k_u - e_u,\quad a_u = k_u,\quad b_u = 1 - k_u - e _u,\quad c_u = 1 - k _u - e _u
t=1−ku−eu,au=ku,bu=1−ku−eu,cu=1−ku−eu
递归处理一遍即可。求出
a
1
,
b
1
,
c
1
a_1,b_1,c_1
a1,b1,c1后,有
f
1
=
a
1
f
1
+
(
b
1
×
0
)
+
c
1
f_1 = a_1f_1 + (b_1 \times 0) + c_1
f1=a1f1+(b1×0)+c1,即答案为
f
1
=
c
1
1
−
a
1
f_1 = \frac{c_1}{1 - a_1}
f1=1−a1c1
注意分母为
0
0
0时输出impossible
.
Code:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1e4 + 50;
const double eps = 1e-9;
int T,n,x,y,cnt,last[maxn],d[maxn];
double a[maxn],b[maxn],c[maxn],k[maxn],e[maxn];
struct Edge{
int v,nxt;
}_e[2 * maxn];
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
return x;
}
inline void insert(int x,int y){
cnt ++,_e[cnt].v = y,_e[cnt].nxt = last[x],last[x] = cnt;
}
bool dfs(int u,int fa){
if(d[u] == 1 && u != 1){//叶子节点,直接赋值
a[u] = k[u],b[u] = 1 - k[u] - e[u],c[u] = 1 - k[u] - e[u];
return 1;
}
double Sa = 0,Sb = 0,Sc = 0;
for(int i = last[u]; i; i = _e[i].nxt){
int v = _e[i].v;
if(v == fa) continue;
if(!dfs(v,u)) return 0;
Sa += a[v],Sb += b[v],Sc += c[v];
}
double t = (1 - k[u] - e[u]) / d[u];
if(fabs(1 - t * Sb) < eps) return 0;//分母为零,无解
a[u] = (k[u] + t * Sa) / (1 - t * Sb);
b[u] = t / (1 - t * Sb);
c[u] = (t * Sc + t * d[u]) / (1 - t * Sb);
return 1;
}
int main(){
T = read();
for(int i = 1; i <= T; i ++){
n = read(),cnt = 0;
for(int i = 1; i <= n; i ++) d[i] = 0,last[i] = 0;
for(int i = 1; i < n; i ++){
x = read(),y = read(),d[x] ++,d[y] ++;
insert(x,y),insert(y,x);
}
for(int i = 1; i <= n; i ++) k[i] = read() / 100.0,e[i] = read() / 100.0;
if(dfs(1,0) && fabs(1 - a[1]) >= eps) printf("Case %d: %f\n",i,c[1] / (1 - a[1]));//有解
else printf("Case %d: impossible\n",i);
}
return 0;
}