• #树形dp,二次扫描换根法#洛谷 4284 [SHOI2014]概率充电器


    题目


    分析

    充电很难做,考虑判断不充电的概率,
    (dp[x])表示点(x)无法充电的概率,但是这样有后效性,
    考虑先处理子树内的问题,那么
    (dp[x]=(1-p[x])prod_{yin son_x}(1-w+dp[y]*w))
    然后考虑换根,那么将父节点对于新的根的贡献去掉然后求答案,
    但是有点恶心的是除数可能为0,所以要特判


    代码

    #include <cstdio>
    #include <cctype>
    #define rr register
    using namespace std;
    const int N=500011; int as[N],n,k=1;
    struct node{
        int y; double w; int next;
    }e[N<<1];
    double f[N],dp[N],ans;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void dfs1(int x,int fa){
    	for (rr int i=as[x];i;i=e[i].next)
    	if (e[i].y!=fa) dfs1(e[i].y,x),
    	    f[x]*=(1+e[i].w*(f[e[i].y]-1));
    }
    inline void dfs2(int x,int Fa){
    	if (x>1){
    		rr double F=0;
    		if (1-f[x]!=1/e[Fa].w) F=dp[e[Fa].y]/(1+e[Fa].w*(f[x]-1));
    		dp[x]=f[x]*(1+e[Fa].w*(F-1));
    	}
    	for (rr int i=as[x];i;i=e[i].next)
    	    if (i!=Fa) dfs2(e[i].y,i^1);
    }
    signed main(){
    	n=iut();
    	for (rr int i=1;i<n;++i){
    		rr int x=iut(),y=iut();
    		rr double w=iut()*0.01;
    		e[++k]=(node){y,w,as[x]},as[x]=k;
    		e[++k]=(node){x,w,as[y]},as[y]=k;
    	}
    	for (rr int i=1;i<=n;++i) f[i]=1-iut()*0.01;
    	dfs1(1,0),dp[1]=f[1],dfs2(1,0);
    	for (rr int i=1;i<=n;++i) ans+=1-dp[i];
    	return !printf("%lf",ans);
    }
    
  • 相关阅读:
    Git查询
    HDU-3038 How Many Answers Are Wrong 并查集
    CodeForcesEducationalRound40-D Fight Against Traffic 最短路
    HDU-6109 数据分割 并查集(维护根节点)
    ZOJ-3261 Connections in Galaxy War 并查集 离线操作
    AtCoderBeginner091-C 2D Plane 2N Points 模拟问题
    HDU-1878 欧拉回路 欧拉回路
    [笔记-图论]Floyd
    [笔记-图论]Bellman-Ford
    [笔记-图论]Dijkstra
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13928805.html
走看看 - 开发者的网上家园