【BZOJ3925】地震后的幻想乡(ZJOI2015)-概率期望+子集状压DP

地震后的幻想乡
做法:本题需要用到概率期望+子集状压DP。
题目要求最小生成树最大边的期望,我们知道这个值等于最大边的期望排名(从小到大)km+1
那么令)
得到这个和式,我们变换它的求和顺序,可得:
)
而最大边)
因为每种x条边使得图不能连通的方案数。
于是我们有了一个定义状态的思路:令jl
其中)
这样我们就可以同时转移)x
于是我们就解决了这一题,时间复杂度为)
以下是本人代码:

#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;
}