1. 程式人生 > >P4284 [SHOI2014]概率充電器

P4284 [SHOI2014]概率充電器

技術 進行 小數 reg 說明 -s double new 潮流

P4284 [SHOI2014]概率充電器

鏈接:https://www.luogu.org/problemnew/show/P4284

題目描述

著名的電子產品品牌SHOI 剛剛發布了引領世界潮流的下一代電子產品—— 概率充電器:

“采用全新納米級加工技術,實現元件與導線能否通電完全由真隨機數決 定!SHOI 概率充電器,您生活不可或缺的必需品!能充上電嗎?現在就試試看 吧!”

SHOI 概率充電器由n-1 條導線連通了n 個充電元件。進行充電時,每條導 線是否可以導電以概率決定,每一個充電元件自身是否直接進行充電也由概率 決定。隨後電能可以從直接充電的元件經過通電的導線使得其他充電元件進行 間接充電。

作為SHOI 公司的忠實客戶,你無法抑制自己購買SHOI 產品的沖動。在排 了一個星期的長隊之後終於入手了最新型號的SHOI 概率充電器。你迫不及待 地將SHOI 概率充電器插入電源——這時你突然想知道,進入充電狀態的元件 個數的期望是多少呢?

輸入輸出格式

輸入格式:

第一行一個整數:n。概率充電器的充電元件個數。充電元件由1-n 編號。

之後的n-1 行每行三個整數a, b, p,描述了一根導線連接了編號為a 和b 的 充電元件,通電概率為p%。

第n+2 行n 個整數:qi。表示i 號元件直接充電的概率為qi%。

輸出格式:

輸出一行一個實數,為能進入充電狀態的元件個數的期望,四舍五入到小 數點後6 位小數。

輸入輸出樣例

輸入樣例#1: 復制
3
1 2 50
1 3 50
50 0 0
輸出樣例#1: 復制
1.000000
輸入樣例#2: 復制
5
1 2 90
1 3 80
1 4 70
1 5 60
100 10 20 30 40
輸出樣例#2: 復制
4.300000

說明

對於30%的數據,n≤5000。

對於100%的數據,n≤500000,0≤p,qi≤100。

題解:概率dp,正難求反,求充不上的概率

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-6
#define maxn 500005
double f[maxn],g[maxn],h[maxn];
int
tot,head[maxn]; struct edge{ int nxt,to;double w; }G[maxn * 2 + 10]; void add(int u, int v, double w){ G[++tot].to = v; G[tot].w = w; G[tot].nxt = head[u]; head[u] = tot; } void dfs1(int u, int fa){//兒子的貢獻 for(int i = head[u]; i; i = G[i].nxt){ int v = G[i].to; if(v == fa)continue; dfs1(v, u); h[v] = f[v] + (1 - f[v]) * (1 - G[i].w);//兒子充不上電的概率+兒子沖上電的概率*導線無電概率 f[u] *= h[v]; } } void dfs2(int u, int fa){ //父親的貢獻 for(int i = head[u]; i; i = G[i].nxt){ int v = G[i].to; if(v == fa)continue; double t = (f[v] < eps) ? 0 : g[u] * f[u]/h[v];//父親充不上電的概率,要出去他本身對父親的貢獻 g[v] = (1 - t)*(1 - G[i].w) + t; dfs2(v, u); } } /* t = g[fa] * f[fa] / f[u] g[u] = t + (1 - t)*(1 - w[fa][u]) */ int main(){ int n; double ans = 0; scanf("%d",&n); for(int i = 1; i < n; i++){ int u, v, c; scanf("%d%d%d",&u,&v,&c); add(u, v, c/100.0);add(v, u, c/100.0); } for(int i = 1; i <= n; i++){ int c;scanf("%d",&c); f[i] = 1 - c/100.0; } dfs1(1, 0); f[0] = 1; g[1] = 1; dfs2(1, 0); for(int i = 1; i <= n; i++) ans += (1 - f[i]*g[i]);//充上的概率=(1-父親、兒子都讓他充不上) printf("%.6lf\n",ans); }

P4284 [SHOI2014]概率充電器