Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 1055 Accepted Submission(s): 347
Special Judge
/**
dp求期望的题。
题意:
有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,
从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的边数的期望值。
设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。
叶子结点:
E[i] = ki*E[1] + ei*0 + (1-ki-ei)*(E[father[i]] + 1);
= ki*E[1] + (1-ki-ei)*E[father[i]] + (1-ki-ei);
非叶子结点:(m为与结点相连的边数)
E[i] = ki*E[1] + ei*0 + (1-ki-ei)/m*( E[father[i]]+1 + ∑( E[child[i]]+1 ) );
= ki*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei)/m*∑(E[child[i]]) + (1-ki-ei);
设对每个结点:E[i] = Ai*E[1] + Bi*E[father[i]] + Ci;
对于非叶子结点i,设j为i的孩子结点,则
∑(E[child[i]]) = ∑E[j]
= ∑(Aj*E[1] + Bj*E[father[j]] + Cj)
= ∑(Aj*E[1] + Bj*E[i] + Cj)
带入上面的式子得
(1 - (1-ki-ei)/m*∑Bj)*E[i] = (ki+(1-ki-ei)/m*∑Aj)*E[1] + (1-ki-ei)/m*E[father[i]] + (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 = ki;
Bi = 1 - ki - ei;
Ci = 1 - ki - ei;
从叶子结点开始,直到算出 A1,B1,C1;
E[1] = A1*E[1] + B1*0 + C1;
所以
E[1] = C1 / (1 - A1);
若 A1趋近于1则无解...
**/
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<cmath> using namespace std; const int N=100010; double e[N],k[N]; double A[N],B[N],C[N]; vector<int> vt[N]; int DFS(int i,int pre){ if(vt[i].size()==1 && pre!=-1){ //计算叶子结点 A[i]=k[i]; B[i]=1-k[i]-e[i]; C[i]=1-k[i]-e[i]; return 1; } A[i]=k[i]; B[i]=(1-k[i]-e[i])/vt[i].size(); C[i]=1-k[i]-e[i]; double tmp=0; for(int j=0;j<(int)vt[i].size();j++){ if(vt[i][j]==pre) continue; if(!DFS(vt[i][j],i)) return 0; A[i]+=A[vt[i][j]]*B[i]; C[i]+=C[vt[i][j]]*B[i]; tmp+=B[vt[i][j]]*B[i]; } if(fabs(tmp-1)<1e-10) return 0; A[i]/=(1-tmp); B[i]/=(1-tmp); C[i]/=(1-tmp); return 1; } int main(){ //freopen("input.txt","r",stdin); int t,n,cases=0; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++) vt[i].clear(); int u,v; for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); vt[u].push_back(v); vt[v].push_back(u); } for(int i=1;i<=n;i++){ scanf("%lf%lf",&k[i],&e[i]); k[i]/=100; e[i]/=100; } printf("Case %d: ",++cases); if(DFS(1,-1) && fabs(1-A[1])>1e-10) printf("%.6lf\n",C[1]/(1-A[1])); else printf("impossible\n"); } return 0; }