• 【Luogu P4284】[SHOI2014]概率充电器


    概率充电器

    链接:

    洛谷

    题目大意:

    在一棵树上,(n) 个节点有直接充电的概率 (q_i),边有帮节点间接充电的概率 (p_{u,v})。求每个点充上电的概率。

    思路:

    直接求充上电的概率不太行,求充不上的概率。设 (f_u) 表示 (u) 不亮的概率:

    [f_u=(1-q_i)prod_{(u,v)in E}(1-p_{u,v}+p_{u,v}f_v) ]

    树形 DP 再套换根即可:

    [f_u=(1-q_i)prod_{vinmathrm{son}(u)}(1-p_{u,v}+p_{u,v}f_v) ]

    (g_u) 表示 (u) 为根时的充不上电的答案:

    [g_u=f_uleft(1-p_{mathrm{fa},u}+p_{mathrm{fa},u}left(frac{g_{mathrm{fa}}}{1-p_{mathrm{fa},u}+p_{mathrm{fa},u}f_u} ight) ight) ]

    代码:

    纪中机子爆栈,用 BFS 打。

    
    const int N = 2e6 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n;
    double p[N], f[N], g[N];
    
    struct edge
    {
    	int to, nxt; double val;
    }e[N << 1];
    int head[N], tot;
    void add (int u, int v, double w)
    {
    	e[++tot] = (edge){v, head[u], w}, head[u] = tot;
    }
    
    int q[N], H, T;
    int fa[N], TO[N];
    
    void bfs1 ()
    {
    	memset (fa, -1, sizeof fa);
    	memset (q, 0, sizeof q);
    	H = 1, T = 0;
    	q[++T] = 1;
    	fa[1] = 0;
    	while(H <= T) 
    	{
    		int u = q[H++];
    		f[u] = 1 - p[u];
    		for (int i = head[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].to;
    			if (~fa[v]) continue;
    			fa[v] = u, TO[v] = i;
    			q[++T] = v;
    		}
    	}
    	for (int i = T; i; i--)
    	{
    		int u = fa[q[i]], v = q[i], j = TO[v];
    		f[u] *= 1 - e[j].val + e[j].val * f[v];
    	}
    	return;
    }
    
    void bfs2 ()
    {
    	g[1] = f[1];
    	memset (q, 0, sizeof q);
    	memset (fa, -1, sizeof fa);
    	H = 1, T = 0;
    	q[++T] = 1;
    	fa[1] = 0;
    	while(H <= T) 
    	{
    		int u = q[H++];
    		for (int i = head[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].to;
    			if (~fa[v]) continue;
    			fa[v] = u;
    			g[v] = f[v] * (1 - e[i].val + e[i].val * (g[u] / (1 - e[i].val + e[i].val * f[v])));
    			q[++T] = v;
    		}
    	}
    	return;
    }
    
    double ans;
    
    int main()
    {
    	n = Read();
    	for (int i = 1; i < n; i++)
    	{
    		int u = Read(), v = Read(); double w;
    		scanf ("%lf", &w); w *= 0.01;
    		add(u, v, w), add(v, u, w);
    	}
    	for (int i = 1; i <= n; i++)
    		scanf ("%lf", &p[i]), p[i] *= 0.01;
    	bfs1 (), bfs2();
    	for (int i = 1; i <= n; i++)
    		ans += 1 - g[i];
    	printf ("%.6f", ans);
    	return 0;
    }
    
  • 相关阅读:
    日常
    hdoj 5690 All X (快速幂+取模)
    hdoj 4004 The Frog's Games(二分)
    Mac androidStudio cannot resolve corresponding JNI function
    Mac 切换JDK版本
    MAC系统 如何显示隐藏的文件(文件夹)
    C 读写文件以及简单的文件加密
    C 双向链表的简单排序实现
    Android ViewDragHelper详解
    android Toast的内容过长,如何居中显示?
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15036627.html
Copyright © 2020-2023  润新知