zoukankan      html  css  js  c++  java
  • LuoGuP4284:[SHOI2014]概率充电器

    Pre

    做了之后看题解发现有人说是一个叫做(up and down)的经典做法。

    (雾)

    Solution

    这道题我是先想成了令(dp[i][0])表示父亲节点没有传入信号时的期望,(dp[i][1])表示父亲节点传入信号时的期望。

    发现没法统计父亲传入的贡献。

    直接统计一个点被激活的概率,不如统计一个点不被激活的概率,再用(1)来减。

    考虑(dp[i])表示这个点没有被激活的期望。并且假装它的父亲节点不存在,也就是只考虑它的子树的贡献。

    那么状态转移

    (dp[i]=(1-p_i)prodlimits_{jin son(i)}EdgeVal_k imes (1-dp[to[j]])+(1-EdgerVal_k))

    具体就是枚举每一个儿子,然后假设边是否可以传导信号,两种情况下转移就是了。

    这样的话,正确性是可以保证的,就是每一个(dp[i])的值是对的,但是现在不能统计出答案。

    然后发现(dp[1])与最终结果中的(dp[1])一样,也就是之后不会再修改(dp[1])了。

    那么考虑哪些点需要被修改。

    一个点被修改一定是父亲节点的贡献没有被统计((1)号节点没有父亲节点)。

    那么考虑把贡献计入每一个点。

    为了再(O(n))时间复杂度完成,需要一些转移。

    假设(pre)表示这个节点的父亲所在的子树的贡献,可以理解为树重构为以(i)为根时,父亲支链上的贡献(此处要考虑相连的这一条边)。

    转移的时候大力转移就可以了。


    至于为什么是正确的,有一个地方。

    因为我们设置的是不被激活的概率,所以在计算的时候不用考虑它对其他节点的贡献。


    Code

    #include <cstdio>
    #include <queue>
    #include <cstring>
    #define ll long long
    #define xx first
    #define yy second
    using namespace std;
    const int N = 500000 + 5;
    int fr[N << 1], to[N << 1], h[N], tot;
    double val[N << 1], p[N];
    double dp[N], dp2[N];
    int n;
    inline void dfs2 (int u, int f, double pre) {
    	dp2[u] = dp[u] * pre;
    	for (int i = h[u]; i; i = fr[i]) {
    		if (to[i] == f) continue;
    		double tmp = pre * dp[u];
    		tmp /= val[i] * dp[to[i]] + (1 - val[i]);
    		tmp = val[i] * tmp + (1 - val[i]);
    		dfs2 (to[i], u, tmp);
    	}
    }
    inline void dfs (int u, int f) {
    	dp[u] = 1 - p[u];
    	for (int i = h[u]; i; i = fr[i]) {
    		if (to[i] == f) continue;
    		dfs (to[i], u);
    		dp[u] *= val[i] * dp[to[i]] + (1 - val[i]);
    	}
    }
    inline void add (int u, int v, double tmp) {
    	tot++;
    	fr[tot] = h[u];
    	to[tot] = v;
    	h[u] = tot;
    	val[tot] = tmp;
    }
    int main () {
    	#ifdef chitongz
    	freopen ("x.in", "r", stdin);
    	#endif
    	scanf ("%d", &n);
    	for (int i = 1; i <= n - 1; ++i) {
    		int x, y;
    		double tp;
    		scanf ("%d%d%lf", &x, &y, &tp);
    		tp /= 100;
    		add (x, y, tp);
    		add (y, x, tp);
    	}
    	for (int i = 1; i <= n; ++i) {
    		scanf ("%lf", &p[i]);
    		p[i] /= 100;
    	}
    	dfs (1, 0);
    	dfs2 (1, 0, 1.0);
    	double ans = 0.0;
    	for (int i = 1; i <= n; ++i) ans += 1 - dp2[i];
    	printf ("%.6lf
    ", ans);
    	return 0;
    }
    

    Conclusion

    思维题。

  • 相关阅读:
    hdu 2147 kiki's game
    HDU 1846 Brave Game
    NYOJ 239 月老的难题
    NYOJ 170 网络的可靠性
    NYOJ 120 校园网络
    xtu字符串 B. Power Strings
    xtu字符串 A. Babelfish
    图论trainning-part-1 D. Going in Cycle!!
    XTU 二分图和网络流 练习题 J. Drainage Ditches
    XTU 二分图和网络流 练习题 B. Uncle Tom's Inherited Land*
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11350298.html
Copyright © 2011-2022 走看看