• Luogu P2081 [NOI2012]迷失游乐园 | 期望 DP 基环树


    题目链接

    基环树套路题。(然而各种错误调了好久233)

    当$m=n-1$时,原图是一棵树。

    先以任意点为根做$dp$,求出从每一个点出发,然后只往自己子树里走时路径的期望长度。

    接着再把整棵树再扫一遍,求出从每一个点出发时路径的期望长度。

    最后再统计一遍答案即可。

    当$m=n$时,原图是一棵基环树。

    先找到图中那唯一的一个环,然后以环上的每一个节点为根在此节点的子树内做$dp$。

    环上节点的数量很少,$dp$之后直接暴力算出从每一个环上节点出发时路径的期望长度。

    然后把每一个环上节点的子树扫一遍,求出从每一个点出发时路径的期望长度。

    最后再统计一遍答案即可。

    #include<iostream>
    #include<cstdio>
    #include<fstream>
        using namespace std;
    struct edge
    {
        int last;
        int end;
        int weight;
    }e[200005];
        int n=0,m=0,root=0;
        int ne=1,cnt[100005],note[100005];
        int tot=0,ring[100005];
        int ringdis[100005];
        bool flag=false,vis[100005],inring[100005];
        double ans=0,f[100005],d[100005];
    void NewEdge(int u,int v,int w)
    {
        ne++;
        e[ne].last=note[u];
        e[ne].end=v;
        e[ne].weight=w;
        note[u]=ne;
    }
    void dfs(int x,int fx)
    {
        cnt[x]=f[x]=0;
        for(int i=note[x];i;i=e[i].last)
        {
            if(e[i].end==fx||inring[e[i].end]) continue;
            dfs(e[i].end,x),cnt[x]++;
        }
        if(cnt[x]==0) return;
        for(int i=note[x];i;i=e[i].last)
        {
            if(e[i].end==fx||inring[e[i].end]) continue;
            f[x]+=e[i].weight+f[e[i].end];
        }
        f[x]/=cnt[x];
    }
    void dfss(int x,int fx,int w)
    {
        if(x==root&&!inring[x]) d[x]=f[x];
        else if(x!=root)
        {
            d[x]=f[x]*cnt[x]/(cnt[x]+1);
            if(fx==root&&cnt[fx]==1) d[x]+=(double)w/(cnt[x]+1);
            else if(fx==root) d[x]+=((d[fx]*cnt[fx]-f[x]-w)/(cnt[fx]-1)+w)/(cnt[x]+1);
            else d[x]+=((d[fx]*(cnt[fx]+1)-f[x]-w)/cnt[fx]+w)/(cnt[x]+1);
        }
        for(int i=note[x];i;i=e[i].last)
        {
            if(e[i].end==fx||inring[e[i].end]) continue;
            dfss(e[i].end,x,e[i].weight);
        }
    }
    void dfsss(int x,int fe)
    {
        if(flag) return;
        vis[x]=true,ring[++tot]=x;
        for(int i=note[x];i;i=e[i].last)
        {
            if(i==(fe^1)) continue;
            if(flag) break;
            if(vis[e[i].end])
            {
                int st=0,ed=tot,h=e[i].end;
                for(int i=1;i<=tot;i++)
                    if(ring[i]==h) {st=i;break;}
                for(int i=st;i<=ed;i++)
                {
                    inring[ring[i]]=true;
                    for(int j=note[ring[i]];j;j=e[j].last)
                        if(e[j].end==((i==ed)?ring[st]:ring[i+1]))
                            {ringdis[i]=e[j].weight;break;}
                }
                for(int i=st;i<=ed;i++) dfs(ring[i],0);
                 for(int i=st;i<=ed;i++)
                {
                    int x=ring[i];
                    d[x]=f[x]*cnt[x]/(cnt[x]+2);
                    int u=i,w=0;
                    double p=1;
                    for(;;)
                    {
                        p/=cnt[ring[u]]+((u==i)?2:1),w=ringdis[u];
                        u=((u+1>ed)?st:(u+1));
                        if(((u+1>ed)?st:(u+1))==i) 
                            {d[x]+=p*(f[ring[u]]+w); break;}
                        else d[x]+=p*(f[ring[u]]*cnt[ring[u]]/(cnt[ring[u]]+1)+w);
                    }
                    u=i,w=0,p=1;
                    for(;;)
                    {
                        p/=cnt[ring[u]]+((u==i)?2:1),w=ringdis[(u-1<st)?ed:(u-1)];
                        u=((u-1<st)?ed:(u-1));
                        if(((u-1<st)?ed:(u-1))==i) 
                            {d[x]+=p*(f[ring[u]]+w); break;}
                        else d[x]+=p*(f[ring[u]]*cnt[ring[u]]/(cnt[ring[u]]+1)+w);
                    }
                }
                for(int i=st;i<=ed;i++)
                    cnt[ring[i]]+=2,root=ring[i],dfss(root,0,0);
                flag=true; break;
            }
            dfsss(e[i].end,i);
        }
        tot--;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u=0,v=0,w=0;
            scanf("%d%d%d",&u,&v,&w);
            NewEdge(u,v,w);
            NewEdge(v,u,w);
        }
        if(m==n-1) root=1,dfs(root,0),dfss(root,0,0);
              else dfsss(1,0);
        for(int i=1;i<=n;i++)
            ans+=(double)1/n*d[i];
        printf("%.5f",ans);
        return 0;
    }
    Luogu P2081
  • 相关阅读:
    npm 操作
    vue 下拉框选中不显示的问题
    VUE项目中遇到的Bug总结
    Websocket练手
    Mysql 去重取最新的一条数据
    C# 一列数的规则如下:1、1、2、3、5、8、13..…...求第30位数是多少,用递归算法实现
    冒泡排序 升序 降序(笔试)
    Sql语句查询成绩大全(Mysql,sqlserver,oracle)常遇笔试题
    C# ,.net 对比两个List的方法 亲测
    C#当前时间加、减指定时间
  • 原文地址:https://www.cnblogs.com/wozaixuexi/p/11216153.html
Copyright © 2020-2023  润新知