期望的大难题,%%ZZZ大佬的解释,不得不说这是一道好题(然而膜题解都没完全看懂,然后就去烦ZZZ大佬)
简单补充几句吧,tmp的理解是个难点,除以tmp的原因是,当我们化简时,子节点也有一个B*f[父节点],这个时候我们化简不掉,怎么办?直接将他放到等式的左边,和f[父节点]合起来,(1-(1-ki-ei)/m*∑(Bj)),这里1就是原来的父节点,然后(1-ki-ei)/m是到这个子节点的概率,乘以Bj。
这是一道树形dp,核心思想是列出dp方程用逆推的方法往前求,将这道图论题转化为数学模型化简
首先这个图有n个点,n-1条边,且两点之间仅有一条边,那么这个图实际上就是一棵树
对于点i:
设f(i)表示在结点i处,要走出迷宫所要走的边数的期望。f(1)即为所求。若点i是叶子节点,则:
f(i)=ki*f(1)+ei*0+(1-ki-ei)*(f(fa)+1)
f(i)=ki*f(1)+(1-ki-ei)*f(fa)+(1-ki-ei) 叶子式若点i非叶子节点,则他有父亲节点fa,和若干个儿子节点son:
f(i)=ki*f(1)+ei*0+(1-ki-ei)/m *(f(fa)+1) + (1-ki-ei)/m * ∑(f(son)+1)
f(i)=ki*f(1)+(1-ki-ei)/m *f(fa)+(1-ki-ei)/m*∑(f(son))+(1-ki-ei); 非叶子式
(∑符号是求和的意思,也就是把所有的孩子加起来)从公式可知求f(i)需要求到f(fa),f(son)
但这是很难求到的,因为要一直往上求,直到f(1),我们要求f(1)来着假设非叶子节点i是j的父亲
设 tmp*f(i)=Ai*f(1)+Bi*f(fa)+Ci; 我们把这个作为基本式 ,tmp是我们要除掉的系数,先不管他在非叶子节点中:
设
f(son) = Aj*f(1)+Bj*f(i)+Cj;
∑(f(son))=∑(Aj*f(1)+Bj*f(i)+Cj);代入非叶子式得
f(i)=ki*f(1)+(1-ki-ei)/m *f(fa)+(1-ki-ei)/m*∑(Aj*f(1)+Bj*f(i)+Cj)+(1-ki-ei);
化为基本式的形式得:
(1-(1-ki-ei)/m*∑(Bj))*f(i)=(ki+(1-ki-ei)/m*∑(Aj))*f(1)+(1-ki-ei)/m *f(fa)+(1-ki-ei+(1-ki-ei)/m*∑(cj));
代入基本式得:
tmp= (1-(1-ki-ei)/m*∑(Bj))
Ai=(ki+(1-ki-ei)/m*∑(Aj))/tmp
Bi=(1-ki-ei)/m/tmp
Ci=(1-ki-ei+(1-ki-ei)/m*∑(cj))/tmp
观察到 Ai,Bi,Ci 只与j有关的Aj,Bj,Cj 和 与i有关的ki,ei 有关
所以从可以叶子开始逆推得到A1,B1,C1
在叶子节点中 易得:
Ai=ki;
Bi=(1-ki-ei);
Ci=(1-ki-ei);而f(1)=A1*f(1)+B1*0+C1;//1的父亲是0
f(1)=C1/(1-A1);
若A1趋近于1则无解
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const double eps=1e-9; struct node { int x,y,next; }a[21000];int last[11000],len; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } double k[11000],e[11000]; double A[11000],B[11000],C[11000]; int tot[11000]; bool dfs(int x,int fa) { A[x]=k[x]; B[x]=(1-k[x]-e[x])/tot[x]; C[x]=1-k[x]-e[x]; double tmp=0; for(int i=last[x];i;i=a[i].next) { int y=a[i].y; if(y!=fa) { if(dfs(y,x)==false)return false; A[x]+=(1-k[x]-e[x])/tot[x] *A[y]; C[x]+=(1-k[x]-e[x])/tot[x] *C[y]; tmp +=(1-k[x]-e[x])/tot[x] *B[y]; } } if(fabs(tmp-1)<eps)return false; A[x]/=(1-tmp); B[x]/=(1-tmp); C[x]/=(1-tmp); return true; } int main() { int T; scanf("%d",&T); for(int tt=1;tt<=T;tt++) { int n,x,y; scanf("%d",&n); len=0;memset(last,0,sizeof(last)); memset(tot,0,sizeof(tot)); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); ins(x,y);ins(y,x); tot[x]++;tot[y]++; } for(int i=1;i<=n;i++) { scanf("%lf%lf",&k[i],&e[i]); k[i]/=100;e[i]/=100; } if(dfs(1,0)==true&&fabs(1-A[1])>eps) printf("Case %d: %.6lf\n",tt,C[1]/(1-A[1])); else printf("Case %d: impossible\n",tt); } return 0; }