zoukankan      html  css  js  c++  java
  • loj2290 随机二分图

    题意:有一个左右各n个点的二分图,对于连边组有一些性质:1号组的一条边,有50%的概率出现。2号组两条边,有50%的概率同时出现,50%的概率同时不出现。3号组两条边,有50%的概率出现第一条,有50%的概率出现第二条。问完美匹配(所有点都有匹配)方案数的期望*2^n。n<=15。

    标程:

     1 #include<cstdio>
     2 #include<map>
     3 using namespace std;
     4 typedef long long ll;
     5 const int mod=1e9+7;
     6 const int inv2=5e8+4;
     7 const int inv4=25e7+2;
     8 const int inv_4=75e7+5;
     9 const int N=1000;
    10 int read()
    11 {
    12     int x=0;char ch=getchar();
    13     while (ch<'0'||ch>'9') ch=getchar();
    14     while ('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    15     return x;
    16 }
    17 struct node{int v,p;node(){}node(int A,int B){v=A;p=B;}}e[N];
    18 map<int,int> mp;
    19 int n,m,op,x,y,cnt,id,id2;
    20 int dp(int zt)
    21 {
    22     if (!zt) return 1;
    23     map<int,int>::iterator t=mp.find(zt);
    24     if (t!=mp.end()) return t->second;
    25     int ans=0;
    26     for (int i=1;i<=cnt;i++)
    27       if ((e[i].v&zt)==e[i].v&&e[i].v*2>zt)
    28         ans=((ll)ans+(ll)dp(zt^e[i].v)*e[i].p%mod)%mod;
    29     return mp[zt]=ans;
    30 }
    31 int main()
    32 {
    33     n=read();m=read();
    34     for (int i=1;i<=m;i++)
    35     {
    36         op=read();x=read();y=read();
    37         id=(1<<x-1)|(1<<n+y-1);
    38         e[++cnt]=node(id,inv2);
    39         if (op) 
    40         {
    41            x=read(),y=read();
    42            id2=(1<<x-1)|(1<<n+y-1);
    43            e[++cnt]=node(id2,inv2);
    44            if (!(id&id2))//有重合端点的话不用考虑 
    45              if (op==1) e[++cnt]=node(id|id2,inv4);
    46              else e[++cnt]=node(id|id2,inv_4);
    47         }    
    48     }
    49     printf("%d
    ",((ll)dp((1<<(2*n))-1)<<n)%mod);
    50     return 0;
    51 }

    易错点:1.注意2和3组的两条边如果有重复端点的话是不用考虑加组合边的,一定不会同时选这两条边。

    题解:dp

    如果都是1号组的点,也就是边没有依赖出现关系。那么直接dp。f[state]表示在state的匹配状态下完美匹配数的期望。

    为了不算重,按照套路应该选取一个特殊点v,比如编号最大点、lowbit等。

    f[state]=sigma(f[state^v^match_v]*p),p=50%,match_v表示与v相连的另一点。

    状态数有sigma(C(n,i)^2)=sigma(C(n,i)*C(n,n-i))=范德蒙德卷积形式=C(2n,n)≈1.6*1e8,用map记录改成记忆化搜索就好了。

    冷静分析第2组点和第3组点的特征:对于第2组点,如果两条边都不选或只选一条,概率则为0和50%和组1的情况一样;但当两条都选时,组1的概率为50%*50%=25%,而实际应该是50%,对策是再加一条包含这两条边的组合边,概率为25%,这样两种加起来就是50%了。

    同理对于第3组点,如果都不选或只选一条,概率是等同于组1的选法。而都选的概率应该是0,于是加一条概率为-25%的组合边。

    按照组1的情况转移即可。

  • 相关阅读:
    查詢一個表中的所有字段,一个表的结构
    二月份工作總結
    导出excel [原创]
    一个it老总对于新人的一点建议
    命名空间的别名
    mssql 格式化时间 [转]
    开发人员一定要加入收藏夹的网站
    sql 导出/入Excel
    hibernate中hbm文件中inverse功能
    详细展示Asp.net页面的生命周期[转]
  • 原文地址:https://www.cnblogs.com/Scx117/p/8762480.html
Copyright © 2011-2022 走看看