zoukankan      html  css  js  c++  java
  • BZOJ 3925 [Zjoi2015]地震后的幻想乡

    题目:http://www.lydsy.com/JudgeOnline/problem.php?

    id=3925

    题意:给定一个nm边的无向图,没有重边和自环。每条边的权值为[0,1]之间的随机变量,求最小生成树中最大边的期望权值。
    n10,mn(n1)2

    题解:依据期望的线性性,我们能够算出随机选前k小的那些边使图恰好连通的概率,则答案为概率之和除以(m+1),由于对于m[0,1]之间的随机变量x1,x2,...,xm,第k小的那个的期望值是km+1
    此题略卡精度。所以我们能够考虑先算出可行方案数。再除以总方案数得到概率。
    cnt[i]表示点集i之间的无向边边数。f[i][j]表示点集为i,选用j条边使点集不连通的方案数,g[i][j]表示点集为i。选用j条边使点集连通的方案数,那么显然有f[i][j]+g[i][j]=(jcnt[i]),而计算f的方法。能够是通过枚举包括点集里某个定点的连通块大小来不重不漏的计数。
    对于计算f[S]。考虑包括点集S中某个定点P的点集T,则TS的真子集且TST之间没有连边。就能够不重不漏地代表S不连通的全部情况。可是两个子点集的边数随意。仅仅用保证T是连通的,那么就有

    f[S][i+j]=TSg[T][i](jcnt[ST])

    这个转移能够通过对子集的枚举做到O(3nm)
    令全集为all。于是答案为
    1m+1i=0mf[all][i](icnt[all])

    这样做用double就能够保证精度了,无需__float128

    代码:

    #include <cstdio>
    const int maxn = 11, maxm = 46;
    int n, m, e[maxn], sz[1 << maxn], cnt[1 << maxn];
    long long c[maxm][maxm], f[1 << maxn][maxm], g[1 << maxn][maxm];
    double ans;
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; ++i)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            --u;
            --v;
            e[u] |= 1 << v;
            e[v] |= 1 << u;
        }
        c[0][0] = 1;
        for(int i = 1; i <= m; ++i)
        {
            c[i][0] = c[i][i] = 1;
            for(int j = 1; j < i; ++j)
                c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
        }
        for(int s = 1; s < 1 << n; ++s)
        {
            sz[s] = sz[s >> 1] + (s & 1);
            if(sz[s] == 1)
            {
                g[s][0] = 1;
                continue;
            }
            for(int i = 0; i < n; ++i)
                if((s >> i) & 1)
                    cnt[s] += sz[e[i] & s];
            cnt[s] >>= 1;
            int lowbit = s & -s;
            for(int t = (s - 1) & s; t; t = (t - 1) & s)
                if(t & lowbit)
                    for(int i = 0; i <= cnt[t]; ++i)
                        for(int j = 0; j <= cnt[s ^ t]; ++j)
                            f[s][i + j] += g[t][i] * c[cnt[s ^ t]][j];
            for(int i = 0; i <= cnt[s]; ++i)
                g[s][i] = c[cnt[s]][i] - f[s][i];
        }
        for(int i = 0; i <= m; ++i)
            ans += (double)f[(1 << n) - 1][i] / c[cnt[(1 << n) - 1]][i];
        ans /= m + 1;
        printf("%.6f
    ", ans);
        return 0;
    }
  • 相关阅读:
    本学期课程总结
    “进度条”博客——第十六周
    “进度条”博客——第十五周
    《梦断代码》阅读笔记03
    第二期冲刺站立会议个人博客16(2016/6/09)
    第二期冲刺站立会议个人博客15(2016/6/08)
    第二期冲刺站立会议个人博客14(2016/6/07)
    第二期冲刺站立会议个人博客13(2016/6/06)
    第二期冲刺站立会议个人博客12(2016/6/05)
    “进度条”博客——第十四周
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7308436.html
Copyright © 2011-2022 走看看