题意:
一棵树上每条边有连通概率,每个点有通电概率,点的通电可以通过边传递,求期望通电的点的次数。
题解:
好题啊。。
首先由期望的线性性可以知道答案就是每个点连通的概率相加。
现在考虑如何求概率。
首先,以任意点为根节点DP可以得出仅考虑一个点的子树这个点的连通概率。考虑怎么统计父节点。
因为是从根节点向下更新,而根节点的连通概率已经知道,可以假设现在父节点的连通概率是已知的。
由概率公式
P(A+B)=P(A)+P(B)−P(A)P(B)
已知父亲通电概率 P(A+B) ,儿子向父亲传送电的概率 P(B) ,父亲不通过该儿子也可以通电的概率 P(A) 可以求出,那么儿子再用概率加法加上父节点给儿子通电的概率就好了。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
typedef pair<int,int> pii;
const int Maxn=5e5+50;
const double eps=1e-9;
double dp[Maxn][3];
int n,P[Maxn];
vector<pii>edge[Maxn];
inline void dfs(int now,int f){
double sum_not_ok=1.0;dp[now][0]=1.0;
for(int e=edge[now].size()-1;e>=0;e--){
int v=edge[now][e].first,w=edge[now][e].second;
if(v==f)continue;
dfs(v,now);
double p_edge=(double)w/100.0;
double t=p_edge*dp[v][0]+(1-p_edge)*(dp[v][0]+dp[v][1]);
dp[now][0]*=t;
}
double p_now=(double)P[now]/100.0;
dp[now][0]=dp[now][0]*(1.0-p_now);
dp[now][1]=1.0-dp[now][0];
}
inline void dfs2(int now,int f){
double p_now=(double)P[now]/100;
for(int e=edge[now].size()-1;e>=0;e--){
int v=edge[now][e].first,w=edge[now][e].second;
if(v==f)continue;
double p_edge=(double)w/100.0;
double t=dp[v][1]*p_edge;
if(1-t<eps)t=0;
else t=(dp[now][1]-t)/(1-t);
dp[v][1]=dp[v][1]+t*p_edge-dp[v][1]*t*p_edge;
dfs2(v,now);
}
}
int main(){
n=read();
for(int i=1;i<n;i++){
int x=read(),y=read(),w=read();
edge[x].push_back(make_pair(y,w));
edge[y].push_back(make_pair(x,w));
}
for(int i=1;i<=n;i++)P[i]=read();
dfs(1,0);
dfs2(1,0);
double ans=0;
for(int i=1;i<=n;i++)
ans+=dp[i][1];
printf("%.6f",ans);
}