zoukankan      html  css  js  c++  java
  • 【BZOJ3925】地震后的幻想乡(ZJOI2015)-概率期望+子集状压DP

    测试地址:地震后的幻想乡
    做法:本题需要用到概率期望+子集状压DP。
    题目要求最小生成树最大边的期望,我们知道这个值等于最大边的期望排名(从小到大)/(m+1),因为提示里说了,m[0,1]内的随机变量的第k小值的期望为km+1
    那么令L为最大边的排名,则有:
    ans=E[L]m+1=1m+1x=1mxP(L=x)
    得到这个和式,我们变换它的求和顺序,可得:
    ans=x=1mP(Lx)
    而最大边x的概率,等于用排名前x1的边不能使图连通的概率,令这个概率为T(x1),我们要求:
    ans=x=0m1T(x)
    因为每种x条边的组合作为排名前x的边的概率是相等的,于是T(x)实际上就等于,用x条边使得图不能连通的方案数,除以所有x条边的组合数。于是问题变成了如何求用x条边使得图不能连通的方案数。
    于是我们有了一个定义状态的思路:令f(i,j)为用(连接点集i内部点的)j条边使得点集i不连通的方案数。我们发现只有这个状态不好转移,因为一般这种连通性状压DP的转移思路都是,通过枚举某个点所在的连通块,来做到不重不漏地枚举。于是我们有另一个状态定义:令g(i,j)为用(连接点集i内部点的)j条边使得点集i连通的方案数,那么令ki的一个包含某定点P的真子集,有以下状态转移方程:
    f(i,j)=kl=0edge(k)g(k,l)Cedge(ik)jl
    其中edge(S)表示连接点集S内部点的边的数量,那么上式的含义其实就是,枚举定点P所在的连通块,求剩下的点集不和该连通块连接的方案数。而我们发现fg的定义是互补的,所以有:
    g(i,j)=Cedge(i)jf(i,j)
    这样我们就可以同时转移fg了。那么令all为全集,答案就为:
    ans=1m+1x=0m1f(all,x)Cedge(all)x
    于是我们就解决了这一题,时间复杂度为O(3nn2)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,a[60],b[60],edge[1210];
    double C[60][60]={0},f[1210][60],g[1210][60];
    
    void init()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&a[i],&b[i]);
    
        C[0][0]=1.0;
        for(int i=1;i<=m;i++)
        {
            C[i][0]=1.0;
            for(int j=1;j<=i;j++)
                C[i][j]=C[i-1][j-1]+C[i-1][j];
        }
    
        for(int i=1;i<(1<<n);i++)
        {
            edge[i]=0;
            for(int j=1;j<=m;j++)
                if ((i&(1<<(a[j]-1)))&&(i&(1<<(b[j]-1))))
                    edge[i]++;
        }
    }
    
    void work()
    {
        for(int i=1;i<(1<<n);i++)
        {
            for(int j=0;j<=edge[i];j++)
            {
                f[i][j]=0.0;
                int lowbit=i&(-i);
                for(int k=((i-1)&i);k;k=((k-1)&i))
                    if (k&lowbit)
                    {
                        for(int l=0;l<=edge[k]&&l<=j;l++)
                            f[i][j]+=g[k][l]*C[edge[i-k]][j-l];
                    }
                g[i][j]=C[edge[i]][j]-f[i][j];
            }
        }
        double ans=0.0;
        for(int i=0;i<m;i++)
            ans+=f[(1<<n)-1][i]/C[edge[(1<<n)-1]][i];
        ans/=(double)(m+1);
        printf("%.6lf",ans);
    }
    
    int main()
    {
        init();
        work();
    
        return 0;
    }
  • 相关阅读:
    查看端口有没有被占用
    微信公众号2()
    How to insert a segment of noise to music file
    puppet practice
    Docker Commands
    LempelZiv algorithm realization
    The algorithm of entropy realization
    Java network programmingguessing game
    Deploy Openstack with RDO and Change VNC console to Spice
    puppet overview
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793311.html
Copyright © 2011-2022 走看看