• bzoj2878 [Noi2012]迷失游乐园——概率期望DP


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

    这个博客写得很好:https://www.cnblogs.com/qt666/p/7252284.html

    其实就是分成子树部分(down)和向上的部分(up)来考虑、转移;

    要想清楚vis的作用等等,还有那个ed的使用,是和fa配套的,也就是只在子树中使用;

    期望就是其他状态的期望和除以总状态数,只要想清楚有些什么状态就很好转移了!

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int const maxn=3e5+5;
    int n,m,fa[maxn],f[maxn],son[maxn],head[maxn],ct,ed[maxn],cir[maxn],cnt,dfn[maxn],tim,b[maxn];
    double down[maxn],up[maxn],ans;
    bool vis[maxn];
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
    }edge[maxn];
    void add(int x,int y,int z)
    {
        edge[++ct]=N(y,head[x],z);head[x]=ct;
        edge[++ct]=N(x,head[y],z);head[y]=ct;
    }
    void dfs_down(int x)
    {
        vis[x]=1;int tot=0;
        for(int i=head[x],v;i;i=edge[i].next)
        {
            if(vis[v=edge[i].to])continue;
            ed[v]=edge[i].w;//
            dfs_down(v);tot++;
            down[x]+=down[v]+edge[i].w;
        }
        if(tot)down[x]/=tot;//
        son[x]=tot;vis[x]=0;//
    }
    void dfs_up(int x,int u)
    {
    //    fa[x]=u;f[x]=1;
    //    if(u&&son[u])up[x]+=(up[u]+down[u]*son[u]-down[x]-ed[x])/son[u]+ed[x];
    //    for(int i=head[x],v;i;i=edge[i].next)
    //        if(!f[v=edge[i].to])ed[v]=edge[i].w,dfs_up(v,x);
        vis[x]=1;if(u) f[x]=1;
        if((son[u]-1+f[u])&&u) up[x]+=(up[u]*f[u]+son[u]*down[u]-down[x]-ed[x])/(son[u]-1+f[u]);//特判根节点(只有一个son的) 
        for(int i=head[x],v;i;i=edge[i].next)
            if(!vis[v=edge[i].to]) /*ed[i]=edge[i].w,*/
                up[v]+=edge[i].w,dfs_up(v,x);//在down时已求出ed 
    }
    void make(int rt,int x)
    {
        for(int i=x;i!=fa[rt];i=fa[i])//不是i!=rt  !!! 
            cir[++cnt]=i,b[cnt+1]=ed[i],f[i]=2,vis[i]=1;//vis在dfs_down中会用 
            //犯蠢把 cir[++cnt]=i 写成 cir[++cnt]=x ,调了半天!!! 
    }
    void tarjan(int x,int ff)
    {
        dfn[x]=++tim;fa[x]=ff;
        for(int i=head[x],v;i;i=edge[i].next)
        {
            if(!dfn[v=edge[i].to])ed[v]=edge[i].w,tarjan(v,x);
            else if(dfn[v]>dfn[x])b[1]=edge[i].w,make(x,v);
        }
    }
    void solve(int x,int j,int step)
    {
        double g=0.5,d=0;
        for(int i=1;i<cnt;i++)//所求的都是up[x]! 
        {
            if(step==-1)d+=b[j];j+=step;//是b而不是ed 
            if(j==0)j=cnt;if(j==cnt+1)j=1;
            if(step==1)d+=b[j];//j+后再+b[j],顺、逆时针有所区分 
            if(i==cnt-1)up[x]+=g*(d+down[cir[j]]);
            else up[x]+=g*(d+down[cir[j]])*son[cir[j]]/(son[cir[j]]+1);
            g/=son[cir[j]]+1;
        }
    }
    void work()//!
    {
        tarjan(1,0);
        for(int i=1;i<=cnt;i++)dfs_down(cir[i]),vis[cir[i]]=1;//
        for(int i=1;i<=cnt;i++)solve(cir[i],i,1),solve(cir[i],i,-1);
        for(int i=1;i<=cnt;i++)dfs_up(cir[i],0);//由于vis,只处理子树 
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y,z;i<=m;i++)
            scanf("%d%d%d",&x,&y,&z),add(x,y,z);
        if(m==n-1)dfs_down(1),dfs_up(1,0);
        else work();
        for(int i=1;i<=n;i++)
            ans+=(down[i]*son[i]+up[i]*f[i])/(son[i]+f[i]);
        printf("%.5lf",ans/n);//ans/n!
        return 0;
    }
  • 相关阅读:
    USACO3.4.3Electric Fence
    (转)《算法艺术与信息学竞赛》题目 提交方式对照表
    UVA10382 Watering
    SGU104 Little shop of flowers
    UVA10673 Play with Floor and Ceil
    SGU123 The sum
    SGU106 The equation
    SGU105 Div 3
    UVA10905 Children's Game
    SGU101 200分类
  • 原文地址:https://www.cnblogs.com/Zinn/p/9143391.html
Copyright © 2020-2023  润新知