• bzoj 2878 [Noi2012]迷失游乐园——树上的期望dp


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2878

    很好的树上概率题的思路,就是分成up和down。

    代码中有众多小细节。让我弃疗好几天的致命小细节是dfs1里面那个sum要定义成double的!……

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define db double
    using namespace std;
    const int N=1e5+5;
    int n,m,head[N],xnt,f[N],son[N],stack[N],top;
    db down[N],up[N];
    bool vis[N],in[N],flag;
    struct Edge{
        int next,to,w;
        Edge(int n=0,int t=0,int w=0):next(n),to(t),w(w) {}
    }edge[N<<1];
    void add(int x,int y,int z)
    {
        edge[++xnt]=Edge(head[x],y,z);head[x]=xnt;
        edge[++xnt]=Edge(head[y],x,z);head[y]=xnt;
    }
    void dfs1(int cr,int fa)
    {
        double sum=0;//double
        for(int i=head[cr],v;i;i=edge[i].next)
            if((v=edge[i].to)!=fa&&!in[v])
            {
                son[cr]++;dfs1(v,cr);
                sum+=down[v]+edge[i].w;//+edge[i].w!!
            }
        if(son[cr])down[cr]=sum/son[cr];
    }
    void dfs2(int cr,int fa,int d)
    {
        if(fa)//判断if(fa)!!
        {
            f[cr]=1;//环上的点fa是0 
            up[cr]=d;   //////如果放在下面的式子里,就少加了d ——但是怎么会有!(son[fa]-1+f[fa])的情况呢? //fa只有一条边的时候! 
            if(son[fa]-1+f[fa])up[cr]+=(down[fa]*son[fa]-d-down[cr]+up[fa]*f[fa])/(son[fa]-1+f[fa]);
    //      printf("cr=%d up=%.5lf(upfa=%.5lf)
    ",cr,up[cr],up[fa]);
        }           //环上的点不求up,已在solve2里求过 
        for(int i=head[cr],v;i;i=edge[i].next)
            if((v=edge[i].to)!=fa&&!in[v])dfs2(v,cr,edge[i].w);
    }
    void tarjan(int cr,int fa)
    {
        stack[++top]=cr;vis[cr]=1;
        for(int i=head[cr],v;i;i=edge[i].next)
            if((v=edge[i].to)!=fa)
            {
                if(vis[v])
                {
                    while(stack[top]!=v)in[stack[top--]]=1;//!=v不是!=cr 
                    in[stack[top--]]=1;flag=1;return;
                }
                else tarjan(v,cr);
                if(flag)return;
            }
        top--;/////////
    }
    void solve(int root,int cr,int fa,double g,int d)/////自己的写法,判cr!=root!! 
    {
        for(int i=head[cr],v;i;i=edge[i].next)
            if(in[v=edge[i].to]&&v!=fa)
            {
                if(v==root)
                {
                    up[root]+=g*(down[cr]+d);//
    //              printf("root=%d cr=%d up=%.5lf(down[cr]=%.5lf g=%.5lf)
    ",root,cr,up[root],down[cr],g);
                    return;
                }
                if(cr!=root)up[root]+=g*(down[cr]+d)*son[cr]/(son[cr]+1);//先+d再乘son[cr] 
    //          printf("root=%d cr=%d up=%.5lf(down[cr]=%.5lf son[cr]=%d g=%.5lf)
    ",root,cr,up[root],down[cr],son[cr],g);
                if(cr==root)solve(root,v,cr,g/2,d+edge[i].w);   //son可能有多个 
                else solve(root,v,cr,g/(son[cr]+1),d+edge[i].w);
            }
    }
    int main()
    {
        scanf("%d%d",&n,&m);int x,y,z;
        if(n==1)
        {
            printf("0.00000");return 0;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);add(x,y,z);
        }
        if(m==n-1)dfs1(1,0),dfs2(1,0,0);
        else{
            tarjan(1,0);
            for(int i=1;i<=n;i++)if(in[i])dfs1(i,0);
            for(int i=1;i<=n;i++)if(in[i])solve(i,i,0,1,0);///!!!!!!!!
            for(int i=1;i<=n;i++)if(in[i])f[i]=2,dfs2(i,0,0);
        }
    //  for(int i=1;i<=n;i++)printf("i=%d up=%.5lf down=%.5lf
    ",i,up[i],down[i]);
        double sum=0;
        for(int i=1;i<=n;i++)sum+=(down[i]*son[i]+up[i]*f[i])/(son[i]+f[i]);
        printf("%.5lf",sum/n);
        return 0;
    }
  • 相关阅读:
    postfix发信提示 Error: too many connectino from
    postfix 设置邮件头翻译,本域邮件不进行邮件头翻译,仅发送至外网的进行邮件头翻译?
    postfix 如何设置邮件头翻译的功能
    postfix 如何设置邮件头翻译的功能
    Oracle VM VirtualBox如何设置网络地址转换NAT
    python提取百度经验<标题,发布时间,平均流量,总流量,具体的链接>
    css 需要阴影的效果
    django POST表单的使用
    Vim中如何使用正则进行搜索
    Nginx 如何设置反向代理
  • 原文地址:https://www.cnblogs.com/Narh/p/9243856.html
Copyright © 2020-2023  润新知