Description
Solution
对每一个点单独算贡献
先定一个树根
设Fi表示只考虑i的子树,i不会被感化的概率
容易写出方程为Fi=(1−Pi)∏j∈son[i](1−qi,j×(1−Fj))
再设Gi表示i不会被它父亲感化的概率,设它父亲为x
容易写出方程为Gi=1−qi,j×(1−Gx+Gx×(1−Fx))
但是如果这样计算G,后面的Fx就会多出来i这个点传上去的影响,所以要除掉
Gi=1−qi,j×(1−Gx+Gx×(1−Fx1−qx,i×(1−Fi)))
注意分母为0不能除
两边DFS解决
时空复杂度O(N)
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 200005
using namespace std;
double f[N],g[N],pr[2*N],fr[N],vl[N];
int fs[N],nt[2*N],dt[2*N],n,m,num;
void link(int x,int y,int z)
{
nt[++m]=fs[x];
dt[fs[x]=m]=y;
pr[m]=z/100.0;
}
void dfs(int k,int fa)
{
f[k]=1-vl[k];
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa)
{
dfs(p,k);
f[k]*=1-pr[i]*(1-f[p]);
}
else fr[k]=pr[i];
}
}
void dp(int k,int fa)
{
if(k==1) g[k]=1;
else
{
double p=f[fa];
if(1-fr[k]*(1-f[k])!=0) p/=(1-fr[k]*(1-f[k]));
g[k]=1-fr[k]*((1-g[fa])+g[fa]*(1-p));
}
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa) dp(p,k);
}
}
int main()
{
cin>>num>>n;
fo(i,1,n-1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
link(x,y,z),link(y,x,z);
}
fo(i,1,n)
{
int x;
scanf("%d",&x);
vl[i]=x/100.0;
}
dfs(1,0);
dp(1,0);
double v=0;
fo(i,1,n) v+=f[i]*g[i];
printf("%.6lf\n",v);
}