题目链接
题意
有n个房间,由n-1条通道连通起来,实际上就形成了一棵树,从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的步数的期望值。
题解
设:i号点走出迷宫步数的期望为
Ei
,父亲为
Fi
,儿子为
Chi
,儿子数目为
m
那么
容易写出:
对于叶子节点i:
Ei=ki∗E1+(1−ki−ei)∗(EFi+1)=ki∗E1+(1−ki−ei)∗EFi+(1−ki−ei)
对于非叶子节点i:
Ei=ki∗E1+(1−ki−ei)/m∗(EFi+1+∑(EChi+1))=ki∗E1+(1−ki−ei)/m∗EFi+(1−ki−ei)/m∗∑EChi+1−ki−ei
我们发现,对于每个点,他的期望都与他父亲的期望和1号点的期望有关。我们可以写出这种形式:
Ei=Ai∗E1+Bi∗EFi+Ci
对于非叶子节点
Ci
的值还与它的儿子有关。设它的儿子为j。
∑Ej=∑(Aj∗E1+Bj∗EFj+Cj)=∑(Aj∗E1+Bj∗Ei+Cj)
将它代入上式:
Ei=ki∗E1+(1−ki−ei)/m∗EFi+(1−ki−ei)/m∗∑(Aj∗E1+Bj∗Ei+Cj)+1−ki−ei
化简后有:
(1−(1−ki−ei)/m∗∑Bj)∗Ei=(ki+(1−ki−ei)/m∗∑Aj)∗E1+(1−ki−ei)/m∗EFi+(1−ki−ei)+(1−ki−ei)/m∗∑Cj
即:
Ai=(ki+(1−ki−ei)/m∗∑Aj)/(1−(1−ki−ei)/m∗∑Bj)Bi=(1−ki−ei)/m/(1−(1−ki−ei)/m∗∑Bj)Ci=((1−ki−ei)+(1−ki−ei)/m∗∑Cj)/(1−(1−ki−ei)/m∗∑Bj)
现在
Ai,Bi,Ci
只与他们的儿子
ki,ei
有关了。于是可以从下往上递推,推出
A1,B1,C1
即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
struct edge{
int x,next;
}ed[20010];
int first[10010],du[10010],tot,n,m,x,y,T,id;
double a[10010],b[10010],c[10010],e[10010],k[10010];
void add(int x,int y){
ed[++tot].x=y;
ed[tot].next=first[x];
first[x]=tot;
}
bool dfs(int x,int y){
int m=du[x];
a[x]=k[x];
b[x]=(1-k[x]-e[x])/m;
c[x]=1-k[x]-e[x];
double tmp=0;
for(int i=first[x];i;i=ed[i].next)
if(ed[i].x!=y){
if(!dfs(ed[i].x,x)) return false;
a[x]+=(1-k[x]-e[x])/m*a[ed[i].x];
c[x]+=(1-k[x]-e[x])/m*c[ed[i].x];
tmp+=(1-k[x]-e[x])/m*b[ed[i].x];
}
if(fabs(tmp-1)<1e-9) return false;
a[x]/=1-tmp;
b[x]/=1-tmp;
c[x]/=1-tmp;
return true;
}
int main(){
for(scanf("%d",&T);T;T--,id++){
memset(first,0,sizeof(first));
memset(du,0,sizeof(du));
scanf("%d",&n); tot=0;
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
du[x]++; du[y]++;
}
for(int i=1;i<=n;i++){
scanf("%lf%lf",&k[i],&e[i]);
k[i]/=100.0; e[i]/=100.0;
}
printf("Case %d: ",id+1);
if(dfs(1,0)&&fabs(1-a[1])>1e-9) printf("%.6f\n",c[1]/(1-a[1]));
else puts("impossible");
}
return 0;
}