题目描述
传送门
题目描述:一棵树,一个人初始在1号点。每次到达一个点,有ki的概率被杀死,并且回到1号点,有ei的概率直接逃离,然后等概率的逃到与他相邻的节点(1-ki-ei)/du[i],每次移动步数+1。 求逃出去的期望步数。
题解
这道题与上面题的思想和方法是类似的。
我们先假设逃离是到达节点0, 那么E[0]=0,倒着推。
对于叶子节点,他要么逃到他的父亲节点,要么被杀,要么直接逃离
E[i]=(1−ki−ei)∗E[fa[i]]+ki∗E[1]+E[0]∗ei
因为E[0]=0 ,所以式子最终可以化简成
E[i]=(1−ki−ei)∗E[fa[i]]+ki∗E[1]+(1−ki−ei)
那么在这个式子中
E[fa[i]],E[1]
是未知量,那么我们可以把式子化简成
E[i]=A[i]∗E[fa[i]]+B[i]∗E[1]+C[i]
的形式。
对于非叶子节点
E[i]=(E[fa[i]]+1+∑(E[son[i]]+1))∗(1−ki−ei)du[i]+E[1]∗ki
对于E[son[i]]来说,如果化成
E[i]=A[i]∗E[fa[i]]+B[i]∗E[1]+C[i]
的形式,那么我们可以发现
E[fa[son[i]]]
实际上就是E[i],那么我们可以对式子进行进一步的化简。
E[i]=(E[fa[i]]+1+∑(A[son[i]]∗E[i]+B[son[i]]∗E[1]+C[son[i]]+1))∗(1−ki−ei)du[i]+E[1]∗ki
我们设
(1−ki−ei)du[i]=p[i]
式子整理得
(1−p[i]∗∑A[son[i]])∗E[i]=p[i]∗E[fa[i]]+(ki+p[i]∗∑B[son[i]])∗E[1]+(1−ki−ei)+p[i]∗∑C[son[i]]
最后把
(1−p[i]∗∑A[son[i]])
除过来,就可以得到
A[i],B[i],C[i]
最后的答案就是
C[1]/(1−B[1])
注意在计算的过程中只要E[i]的系数趋近与0,那就是impossible
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 200003
#define eps 1e-9
using namespace std;
int n,point[N],v[N],nxt[N],du[N],tot,T;
double A[N],B[N],C[N],k[N],e[N];
void add(int x,int y)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
bool dfs(int x,int fa)
{
A[x]=(1-k[x]-e[x])/du[x];
B[x]=k[x];
C[x]=1-k[x]-e[x];
double t=1.0; double h=A[x];
for (int i=point[x];i;i=nxt[i]) {
if (v[i]==fa) continue;
if (!dfs(v[i],x)) return false;
t-=h*A[v[i]];
B[x]+=h*B[v[i]];
C[x]+=h*C[v[i]];
}
if (fabs(t)<eps) return false;
A[x]/=t; B[x]/=t; C[x]/=t;
// cout<<x<<" "<<A[x]<<" "<<B[x]<<" "<<C[x]<<endl;
return true;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&T);
for (int t=1;t<=T;t++) {
tot=0; scanf("%d",&n);
memset(point,0,sizeof(point));
memset(du,0,sizeof(du));
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
memset(C,0,sizeof(C));
for (int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
add(x,y); 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;
}
bool pd=dfs(1,0);
printf("Case %d: ",t);
if (fabs(1.0-B[1])<eps||!pd) printf("impossible\n");
else printf("%.6lf\n",C[1]/(1-B[1]));
}
}