[SHOI2014]概率充电器

· 题解

  首先考虑设ƒi为i发光的概率,那么它可以从子节点、自身、和父节点传过来,但是,这是其中至少有一个通电的问题,也就是“或”,因为它们的目的是一样的——都是使当前通电,也就是说它们并不是互斥的状态,比如子节点和父节点都是50%,那么这个节点的通电概率就是100%了吗?显然不是,虽然有这个公式:

                

  难写,所以不接受。但是,假如我们只看无法通电的概率呢?这样就满足乘法原理了。

  有了这个,简单树形DP换根即可。

· 代码

  

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 const int MAXN = 5e05 + 10;
  8 
  9 struct LinkedForwardStar {
 10     int to;
 11     double w;
 12     
 13     int next;
 14 } ;
 15 
 16 LinkedForwardStar Link[MAXN << 1];
 17 int Head[MAXN]= {0};
 18 int size = 0;
 19 
 20 void Insert (int u, int v, double w) {
 21     Link[++ size].to = v;
 22     Link[size].w = w;
 23     Link[size].next = Head[u];
 24     
 25     Head[u] = size;
 26 }
 27 
 28 const int Root = 1;
 29 
 30 int N;
 31 
 32 double Dire[MAXN];
 33 
 34 double f[MAXN];
 35 
 36 void DFS1 (int root, int father) {
 37     f[root] = 1 - Dire[root];
 38     
 39     for (int i = Head[root]; i; i = Link[i].next) {
 40         int v = Link[i].to;
 41         double w = Link[i].w;
 42         
 43         if (v == father)
 44             continue;
 45         
 46         DFS1 (v, root);
 47         
 48         f[root] *= f[v] + (1 - f[v]) * (1 - w);
 49     }
 50 }
 51 
 52 double g[MAXN];
 53 
 54 void DFS2 (int root, int father, double fval) {
 55     double fp = g[father] * (f[father] / (f[root] + (1 - f[root]) * (1 - fval)));
 56     g[root] = fp + (1 - fp) * (1 - fval);
 57     
 58     for (int i = Head[root]; i; i = Link[i].next) {
 59         int v = Link[i].to;
 60         double w = Link[i].w;
 61         
 62         if (v == father)
 63             continue;
 64         
 65         DFS2 (v, root, w);
 66     }
 67 }
 68 
 69 int main () {
 70     scanf ("%d", & N);
 71     
 72     for (int i = 1; i < N; i ++) {
 73         int u, v, w;
 74         scanf ("%d%d%d", & u, & v, & w);
 75         
 76         double neww = (double) w / 100.0;
 77         Insert (u, v, neww), Insert (v, u, neww);
 78     }
 79     
 80     for (int i = 1; i <= N; i ++) {
 81         int w;
 82         scanf ("%d", & w);
 83         
 84         Dire[i] = (double) w / 100.0;
 85     }
 86     
 87     DFS1 (Root, 0);
 88     g[1] = 1.0;
 89     DFS2 (Root, 0, 0);
 90     
 91     double ans = 0.0;
 92     for (int i = 1; i <= N; i ++)
 93         ans += (1 - f[i] * g[i]);
 94     
 95     printf ("%.6f\n", ans);
 96     
 97     return 0;
 98 }
 99 
100 /*
101 3
102 1 2 50
103 1 3 50
104 50 0 0
105 */
106 
107 /*
108 5
109 1 2 90
110 1 3 80
111 1 4 70
112 1 5 60
113 100 10 20 30 40
114 */
View Code

猜你喜欢

转载自www.cnblogs.com/Colythme/p/9717731.html