题目:点击打开链接
树形概率dp,刚开始以为每个点的概率应该是其他点对其概率贡献加和,然后WA
看了题解才明白并不是,两个事件的并事件的概率应为
P(a | b) = P(a) + P(b) - P(ab)
独立事件 P(ab) = P(a) * P(b)
举个样例
3
1 2 50
1 3 50
0 1 1
并不能认为1充电的概率是1的
求概率的时候把直接加换成上式就可以了
#include<bits/stdc++.h>
using namespace std;
struct node{
int ne;
double cost;
double pp;
node(int u, double v){
ne = u;
cost = v;
pp = 0;
}
node(){
}
};
const int maxn = 5e5 + 10;
double p[maxn], ans = 0, pself[maxn];
vector<node>w[maxn];
double ADD(double a1, double a2){
return a1 + a2 - a1 * a2;
}
double dfs1(int fa, int x){
double p1 = 0;
for(int i = 0; i < w[x].size(); i++){
if(w[x][i].ne == fa)
continue;
w[x][i].pp = w[x][i].cost * dfs1(x, w[x][i].ne);
p1 = ADD(p1, w[x][i].pp);
}
p[x] = p1;
return ADD(p1, pself[x]);
}
void dfs2(int fa, double fp, int x){
ans += ADD(fp, ADD(p[x], pself[x]));
// cout << x << " " << fp + p[x] + pself[x] << endl;
for(int i = 0; i < w[x].size(); i++){
if(w[x][i].ne == fa)
continue;
double temp1;
if(fabs(1 - w[x][i].pp) <= 1e-9) //这里没判除零改了很长时间
temp1 = 0;
else
temp1 = (p[x] - w[x][i].pp) / (1 - w[x][i].pp);
dfs2(x, (ADD(temp1, ADD(pself[x], fp))) * w[x][i].cost, w[x][i].ne);
}
return ;
}
int main(){
int n, a, b;
double pp;
cin >> n;
for(int i = 1; i < n; i++){
scanf("%d %d %lf", &a, &b ,&pp);
node u1(b, pp / 100.0);
node u2(a, pp / 100.0);
w[a].push_back(u1);
w[b].push_back(u2);
}
for(int i = 1; i <= n; i++){
scanf("%lf", &pp);
pself[i] = pp / 100.0;
}
dfs1(0, 1);
// for(int i = 1; i <= n; i++){
// cout << i << ":" << p[i] << endl;
// }
dfs2(0, 0, 1);
printf("%.6lf\n", ans);
return 0;
}
还有一种更优秀的方法是求每个点不能充电的概率,这个概率其实就是每个点不能给这个节点充电的概率和
这样精度肯定比上诉方法优秀,写起来也简单。