bzoj3566(概率+树形DP)

显然答案要把所有通电的概率加起来。。那么问题就是算概率了。。

概率其实来源于所有点的直接通电概率乘上到当前点的路径都通电的概率。。当然这些概率显然不是相加,计算用

考虑2个事件(概率为x和y)至少一个发生的概率为p=1-(1-x)(1-y)=x+y-xy

反解易得x=1-(1-p)/(1-y)

然后一个个点算肯定不行。。不过可以先算根的。。在这个过程中保存子节点通电到子树根节点的通电概率。。

然后根节点的算出来了。。剩下的节点其实就只剩下从父亲到自己的概率没算了。。这个概率可以通过反解得到,然后再来一遍 dfs 就行了。。

/**
 *          ┏┓    ┏┓
 *          ┏┛┗━━━━━━━┛┗━━━┓
 *          ┃       ┃  
 *          ┃   ━    ┃
 *          ┃ >   < ┃
 *          ┃       ┃
 *          ┃... ⌒ ...  ┃
 *          ┃              ┃
 *          ┗━┓          ┏━┛
 *          ┃          ┃ Code is far away from bug with the animal protecting          
 *          ┃          ┃   神兽保佑,代码无bug
 *          ┃          ┃           
 *          ┃          ┃        
 *          ┃          ┃
 *          ┃          ┃           
 *          ┃          ┗━━━┓
 *          ┃              ┣┓
 *          ┃              ┏┛
 *          ┗┓┓┏━━━━━━━━┳┓┏┛
 *           ┃┫┫       ┃┫┫
 *           ┗┻┛       ┗┻┛
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 500005
#define nm 1000005
#define N 1000005
#define M(x,y) x=max(x,y)
const double pi=acos(-1);
const int inf=1e9+7;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
 


struct edge{int t;double v;edge*next;}e[nm],*h[NM],*o=e;
void add(int x,int y,double v){o->t=y;o->v=v;o->next=h[x];h[x]=o++;}
int n,m,_x,_y,f[NM];
double _t,ans,d[NM],p[NM];


void dfs1(int x){
    link(x)if(f[x]!=j->t){
	f[j->t]=x;
	dfs1(j->t);
	d[x]=d[x]+d[j->t]*j->v-d[x]*d[j->t]*j->v;
    }
}

void dfs2(int x){
    link(x)if(f[x]!=j->t){
	double t;if(j->v*d[j->t]+eps<1)t=1-(1-p[x])/(1-d[j->t]*j->v);else t=1;
	p[j->t]=d[j->t]+t*j->v-t*j->v*d[j->t];
	dfs2(j->t);
    }
}

int main(){
    n=read();
    inc(i,1,n-1){_x=read();_y=read();_t=read()/100.0;add(_x,_y,_t);add(_y,_x,_t);}
    inc(i,1,n)d[i]=read()/100.0;
    dfs1(1);p[1]=d[1];dfs2(1);
    inc(i,1,n)ans+=p[i];
    //inc(i,1,n)printf("%.10lf\n",p[i]);
    return 0*printf("%.6lf\n",ans);
}

3566: [SHOI2014]概率充电器

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 1725  Solved: 760
[Submit][Status][Discuss]

Description

著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看吧!

SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定。
随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。
作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。
你迫不及待地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?

Input

第一行一个整数:n。概率充电器的充电元件个数。充电元件由 1-n 编号。
之后的 n-1 行每行三个整数 a, b, p,描述了一根导线连接了编号为 a 和 b 的
充电元件,通电概率为 p%。
第 n+2 行 n 个整数:qi。表示 i 号元件直接充电的概率为 qi%。

Output

输出一行一个实数,为进入充电状态的元件个数的期望,四舍五入到六位小数

Sample Input

3
1 2 50
1 3 50
50 0 0

Sample Output

1.000000

HINT

对于 100%的数据,n≤500000,0≤p,qi≤100。
 

Source

By 佚名提供

[Submit][Status][Discuss]



猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/81435743