记录……记录……
题意:给定n个点,n-1个连接点,保证n个点都能连接起来,在每个点都有ki的概率回到第一个点,有ei的概率找到出口,问从1出发到出口的期望是多少
思路:实际是连成了一个树,那么分别考虑叶结点,非叶结点
设E[i]为当前在i结点到走出迷宫的期望,那么E[1]就是我们所求的
叶结点:E[i]=ki*E[1]+(1-ki-ei)*(E[father[i]]+1)=ki*E[1]+(1-ki-ei)*E[father[i]]+(1-ki-ei)
非叶结点:E[i]=ki*E[1]+(1-ki-ei)/m*(E[father[i]]+1)+(1-ki-ei)/m*∑(E[son[i]]+1)
=ki*E[1]+(1-ki-ei)/m*E[father[i]]+(1-ki-ei)/m*∑(E[son[i]])+(1-ki-ei)
可以看出这两个公式都十分复杂,都带有E[1]、E[father[i]]及E[son[i]]等未知量,同时i又是son[i]的父亲结点,所以我们可以设:
E[i]=Ai*E[1]+Bi*E[father[i]]+Ci,设son[i]=j,那么:
∑(E[son[i]])=∑(E[j])=∑(Aj*E[1]+Bj*E[father[j]]+Cj)=∑(Aj*E[1]+Bj*E[i]+Cj),把这个式子带进非叶结点的式子:
E[i]=ki*E[1]+(1-ki-ei)/m*E[father[i]]+(1-ki-ei)/m*∑(Aj*E[1]+Bj*E[i]+Cj)+(1-ki-ei)
即(1-(1-ki-ei)/m*∑Bj)*E[i]=(ki+(1-ki-ei)/m*∑Aj)+(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]了,即E[1]=A1*E[1]+B1*0+C1,E[1]=C1/(1-A1)
在计算时用递归来计算,同时每次判断一下1-(1-ki-ei)/m*Bj及最后的1-A1是否等于零,如果有零出现,那么就意味着走不到出口了
完整代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=10005;
const double eps=1e-9;
vector<int> vec[maxn];
double k[maxn],e[maxn];
double A[maxn],B[maxn],C[maxn];
bool solve(int x,int pre)
{
int n=vec[x].size();
A[x]=k[x];
B[x]=(1-k[x]-e[x])/n;
C[x]=1-k[x]-e[x];
double tmp=0;
for(int i=0;i<n;i++)
{
int v=vec[x][i];
if(v==pre) continue;
if(!solve(v,x)) return false;
A[x]+=(1-k[x]-e[x])/n*A[v];
C[x]+=(1-k[x]-e[x])/n*C[v];
tmp+=(1-k[x]-e[x])/n*B[v];
}
if(fabs(1-tmp)<eps) return false;
A[x]/=(1-tmp);
B[x]/=(1-tmp);
C[x]/=(1-tmp);
return true;
}
int main()
{
int t;
scanf("%d",&t);
int cnt=0;
while(t--)
{
cnt++;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
vec[i].clear();
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
vec[a].push_back(b);
vec[b].push_back(a);
}
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&k[i],&e[i]);
k[i]/=100;
e[i]/=100;
}
if(solve(1,-1)&&fabs(1-A[1])>eps)
{
printf("Case %d: %.6f\n",cnt,C[1]/(1-A[1]));
}
else printf("Case %d: impossible\n",cnt);
}
return 0;
}