做了有些概率和期望的题目了,现在觉得大致有那么两种办法。【说白了还是要靠数学
一、直接利用组合计数求解。
二、通过状态转移列出方程来,如果能递推就直接DP,不能的话,通过对式子处理,找出式子之间的关系和结构上的特点,通过待定系数来进行迭代,最后求出结果。
。。。再有的话就是用容斥啊状压啊什么的【估计自己也不一定想得到
言归正传来说题吧,我把自己的思路写在注释里了。
参考题解:点击打开链接
/*
* 设dp[i]为从i出发成功逃生的步数的期望值。
* 那么dp[i] = ki * dp[1] + (1 - ki - ei) / m * sigma(dp[j] + 1);(m为i的度数,j是i的相邻节点)
* 整理得, dp[i] = ki * dp[1] + (1 - ki - ei) / m * sigma(dp[j]) + (1 - ki - ei) / m。
*
* 高斯消元显然会超时,所以要考虑父节点和子节点的关系。
*
* 叶子节点:dp[i] = ki * dp[1] + (1 - ki - ei) * dp[father[i]] + 1 - ki - ei.
* 非叶子节点:dp[i] = ki * dp[1] + (1 - ki - ei) / m * sigma(dp[child[i]]) + (1 - ki - ei) / m * dp[father[i]] + (1 - ki - ei) / m
* 对于dp[child[i]],可以用dp[i]表示。
* 这样一来,dp[i] 可以表示成 A * dp[1] + B * dp[father[i]] + C
* 然后从叶子节点不断往上推,直到1节点为止。
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<cstdlib>
using namespace std;
const int maxn = 10005;
const double eps = 1e-9;
struct Nod{
int b,next;
void init(int b,int next){
this->b = b;
this->next = next;
}
}buf[maxn<<2];
int len,head[maxn];
int n,deg[maxn],M[maxn],num[maxn];
double A[maxn],B[maxn],C[maxn],K[maxn],E[maxn];
queue<int> que;
void init(){
memset(num,-1,sizeof(num));
memset(head,-1,sizeof(head));
memset(deg,0,sizeof(deg));
len = 0;
}
void DFS(int x,int &cnt){
num[x] = cnt++;
for(int i = head[x] ; i != -1 ;i = buf[i].next){
int v = buf[i].b;
if(num[v] != -1) continue;
DFS(v,cnt);
}
}
void solve(){
int cnt = 0;
DFS(1,cnt);
for(int i = 2; i <= n ; i++)
if(deg[i] == 1) que.push(i);
while(!que.empty()){
int v = que.front();que.pop();
//cout<<v;
deg[v]--;
A[v] = K[v];B[v] = (1 - K[v] - E[v]) / M[v] ; C[v] = 1 - K[v] - E[v];
//cout<<v<<" : "<<A[v]<<" "<<B[v]<<" "<<C[v]<<endl;
double t = 1,tmp = B[v];
for(int i = head[v] ; i != -1 ; i = buf[i].next){
int u = buf[i].b;
if(num[u] < num[v]){
//cout<<" : "<<u<<endl;
deg[u]--;
if(u != 1 && deg[u] == 1) que.push(u);
if(u == 1 && deg[u] == 0) que.push(1);
continue;
}
deg[u]--;
A[v] += tmp * A[u];
C[v] += tmp * C[u];
t -= tmp * B[u];
}
A[v] /= t;B[v] /= t;C[v] /= t;
//cout<<A[v]<<" "<<B[v]<<" "<<C[v]<<endl;
}
if(fabs(1.0 - A[1]) < eps) printf("impossible\n");
else printf("%.6f\n",C[1] / (1 - A[1]));
}
void add_Edge(int a,int b){
buf[len].init(b,head[a]);head[a] = len++;
buf[len].init(a,head[b]);head[b] = len++;
deg[a]++;deg[b]++;
}
int main(){
int cas;
scanf("%d",&cas);
for(int T = 1; T <= cas; T++){
init();
scanf("%d",&n);
int a,b;
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
add_Edge(a,b);
}
memcpy(M,deg,sizeof(deg));
for(int i=1;i<=n;i++){
scanf("%lf%lf",&K[i],&E[i]);
K[i] /= 100;E[i] /= 100;
}
printf("Case %d: ",T);
solve();
}
return 0;
}