• 题解 洛谷 P4547 【[THUWC2017]随机二分图】


    根据题意,题目中所求的即为所有(n!)种完美匹配的各自的出现概率之和再乘上(2^n)的值。

    发现(n)很小,考虑状压(DP)。设(f_{S,T})为左部图匹配情况为(S),右部图匹配情况为(T)的期望,可以得到转移为:

    [ f_{S,T}=sum_{x subseteqq S land y subseteqq T }f_{S oplus x,T oplus y} imes p_e ]

    其中(x,y)为边(e)的在两个部图的两个端点,(p_e)为这条边的出现概率,转移的含义为加上(e)这条边后(x)(y)实现了匹配。

    发现直接这样转移会算重,所以要事先固定一种转移顺序,可以是每次在(S)中去除最高位来转移,也就是从低位向高位转移,这样就保证不会算重了。

    然后考虑如何解决每条边的出现概率,第一组边不用特殊考虑,概率为(frac{1}{2})。考虑是否可以把第二组和第三组边也转化为第一种的形式。可以先将第二组和第三组边的两条边都以概率为(frac{1}{2})加入,对于第二组边,这时两条边同时出现的概率为(frac{1}{4}),不符合题目(frac{1}{2})的要求,因此再加入同时选这两条边的情况,概率为(frac{1}{4}),对于第三组边,再加入同时选这两条边的情况,概率为(-frac{1}{4})。根据期望的线性性,发现这样处理是正确的,并且恰好符合了题目的要求。

    第二组和第三组边中,若两条边有交集,即两条边为一个点连向另外两个点,此时是不用加上同时选这两条边的情况的,因为题目所求为完美匹配,一个点匹配两个点的情况是不存在的。

    处理完边后,记忆化搜索来实现状压(DP)即可。

    (code:)

    #include<bits/stdc++.h>
    #define maxs 70010
    #define p 1000000007
    #define inv2 500000004
    #define inv4 250000002
    #define sta(x) (1<<(x-1))
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,cnt;
    map<int,ll> f[maxs];
    struct node
    {
        ll s,t,v;
    }e[maxs];
    ll dp(int S,int T)
    {
        if(!S) return 1;
        if(f[S].count(T)) return f[S][T];
        for(int i=1;i<=cnt;++i)
        {
            ll s=e[i].s,t=e[i].t,v=e[i].v;
            if((S|s)!=S||(T|t)!=T||S>=(s<<1)) continue;
            f[S][T]=(f[S][T]+dp(S^s,T^t)*v%p)%p;
        }
        return f[S][T];
    }
    int main()
    {
        read(n),read(m);
        for(int i=1;i<=m;++i)
        {
            int opt,x,y;
            read(opt),read(x),read(y),e[++cnt]=(node){sta(x),sta(y),inv2};
            if(opt)
            {
                read(x),read(y);
                if(!((sta(x)&e[cnt].s)||(sta(y)&e[cnt].t)))
                {
                    cnt++;
                    if(opt==1) e[cnt]=(node){sta(x)|e[cnt-1].s,sta(y)|e[cnt-1].t,inv4};
                    else e[cnt]=(node){sta(x)|e[cnt-1].s,sta(y)|e[cnt-1].t,p-inv4};
                }
                e[++cnt]=(node){sta(x),sta(y),inv2};
            }
        }
        printf("%lld",dp((1<<n)-1,(1<<n)-1)*(1<<n)%p);
        return 0;
    }
    
  • 相关阅读:
    个人vim配置文件
    ORA-4031错误 解决方法
    HashMap在高并发下引起的死循环
    优先队列的应用
    java导入大量Excel时报错
    软件设计师必备——操作系统&#183;
    Java Security安全系列文档翻译笔记————KeyStore、密钥、证书、命令行实战
    能变成有钱人的五个金玉良言(转)
    c3p0链接池
    js中获取键盘事件
  • 原文地址:https://www.cnblogs.com/lhm-/p/13196767.html
Copyright © 2020-2023  润新知