Maze

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 2840    Accepted Submission(s): 1210
Special Judge

Problem Description

When wake up, lxhgww find himself in a huge maze.
The maze consisted by N rooms and tunnels connecting these rooms. Each pair of rooms is connected by one and only one path. Initially, lxhgww is in room 1. Each room has a dangerous trap. When lxhgww step into a room, he has a possibility to be killed and restart from room 1. Every room also has a hidden exit. Each time lxhgww comes to a room, he has chance to find the exit and escape from this maze.
Unfortunately, lxhgww has no idea about the structure of the whole maze. Therefore, he just chooses a tunnel randomly each time. When he is in a room, he has the same possibility to choose any tunnel connecting that room (including the tunnel he used to come to that room).
What is the expect number of tunnels he go through before he find the exit?

Input

First line is an integer T (T ≤ 30), the number of test cases.
At the beginning of each case is an integer N (2 ≤ N ≤ 10000), indicates the number of rooms in this case.
Then N-1 pairs of integers X, Y (1 ≤ X, Y ≤ N, X ≠ Y) are given, indicate there is a tunnel between room X and room Y.
Finally, N pairs of integers Ki and Ei (0 ≤ Ki, Ei ≤ 100, Ki + Ei ≤ 100, K1 = E1 = 0) are given, indicate the percent of the possibility of been killed and exit in the ith room.

Output

For each test case, output one line “Case k: ”. k is the case id, then the expect number of tunnels lxhgww go through before he exit. The answer with relative error less than 0.0001 will get accepted. If it is not possible to escape from the maze, output “impossible”.

Sample Input


3 3 1 2 1 3 0 0 100 0 0 100 3 1 2 2 3 0 0 100 0 0 100 6 1 2 2 3 1 4 4 5 4 6 0 0 20 30 40 30 50 50 70 10 20 60


Sample Output


Case 1: 2.000000 Case 2: impossible Case 3: 2.895522


Source

​The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest ​



        大致题意:有一个n个房间的迷宫,一开始你在1号房间,然后有n-1条通道,走到每一个房间都有一定的概率被杀死,或者在这个房间找到出口。然后每次通向相邻的通道有是等概率的。而且每次被杀死之后就会重新回到1号房间,重新走。问你从1号房间开始,直到走出这个迷宫,期望要走多少个这样的通道。

        看到这题的时候联想到15年长春regional的机器狗那题,同样也是一个在树上求期望的题目。与是仿照那题一样的分别求从根到任意点和从任意点到根的期望。但是在计算的过程中一环套一环实在比较难以实现。于是看了Kuangbin巨巨的博客,才发现了对于这一类树上求期望问题的套路与方法。

        设 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则无解...个这样的通道。

总结一下,这种方法就是说对于一个期望值的表达式的系数进行分类,本题就是把表达式分为了E[1]的系数,E[fa]的系数和其他。对于其他的题,可以用类似的分类方法,然后求出每一项系数的递推式,进而可以用在dfs的同时来求出各项系数,得到最终的期望值。当然了这样子做得有一些前提条件,比如说那个15年长春的那题,其实并不能用这种方法去解。我们也看到了,本题在计算系数的时候要除以某一个东西,当这个东西为0的时候就无解。但是有的题目要除的东西恒为0,这样的话我们也不能说这道题目都是误解的,说明用这种方法解不了。所以说还是得综合考虑求期望的方法。具体见代码:

#include<bits/stdc++.h>
#define DB double
#define eps 1e-9
#define N 10010

using namespace std;

DB a[N],b[N],c[N],e[N],k[N];
vector<int> g[N];
int size[N],n;

bool dfs(int x,int fa)
{
int sz=g[x].size();
DB s=0; a[x]=k[x];
c[x]=1-e[x]-k[x]; b[x]=c[x]/sz;
for(int i=0;i<sz;i++)
{
int y=g[x][i];
if (y==fa) continue;
if (!dfs(y,x)) return 0;
s+=(1-k[x]-e[x])/sz*b[y];
a[x]+=(1-k[x]-e[x])/sz*a[y];
c[x]+=(1-k[x]-e[x])/sz*c[y];
}
if (fabs(1-s)<eps) return 0;
s=1-s; a[x]/=s; b[x]/=s; c[x]/=s;
return 1;
}

void init()
{
memset(g,0,sizeof(g));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
}

int main()
{
int T_T;
int T=0;
cin>>T_T;
while(T_T--)
{
init();
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v; scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&k[i],&e[i]);
k[i]/=100.; e[i]/=100.;
}
DB ans=0;
if (dfs(1,0)&&fabs(1-a[1])>eps) ans=c[1]/(1-a[1]);
if (ans) printf("Case %d: %.6f\n",++T,ans);
else printf("Case %d: impossible\n",++T);
}
return 0;
}