• [bzoj2891]匹配难题


    记$HS$为(左部点中)所有存在完美匹配的点集(所构成的集合)

    定义$f_{i,HS}$表示右部前$i$个点且状态为$HS$的概率,考虑转移——

    记$i$的边集为$N$,枚举所匹配的点,可得$HS'=HS\cup \{S\cup \{x\}\mid x\in N,S\in HS\}$

    关于如何求$HS$,可以用$2^{n}$位二进制表示(map存储),并做到单次$o(a)$(位运算)

    换言之,转移即$P(i,N)\cdot f_{i-1,HS}\rightarrow f_{i,HS}$(其中$P(i,N)$表示$i$边集为$N$的概率)

    同时,从$HS=\{\empty\}$出发,经过上述转移后不同的$HS$仅有$f(a)\le 3762$种

    总复杂度为$o(2^{a}f(a)\times (a+\log f(a)+b))$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 105
     4 #define M 40000
     5 #define ull unsigned long long
     6 int n,m,t;double ans,p[N][6],P[1<<6],g[M],f[M];
     7 ull HSi[6],tr[M][1<<6];queue<ull>q;
     8 map<ull,int>id;map<ull,int>::iterator it;
     9 int main(){
    10     scanf("%d%d",&n,&m);
    11     if (n<=m){
    12         for(int i=0;i<n;i++)
    13             for(int j=1;j<=m;j++)scanf("%lf",&p[j][i]);
    14     }
    15     else{
    16         swap(n,m);
    17         for(int j=1;j<=m;j++)
    18             for(int i=0;i<n;i++)scanf("%lf",&p[j][i]);
    19     }
    20     for(int i=0;i<n;i++)
    21         for(int S=0;S<(1<<n);S++)
    22             if ((S>>i)&1^1)HSi[i]|=((ull)1<<S);
    23     t=id[1]=1,q.push(1);
    24     while (!q.empty()){
    25         ull HS=q.front();q.pop();
    26         for(int S=0;S<(1<<n);S++){
    27             ull HS0=HS;
    28             for(int i=0;i<n;i++)
    29                 if ((S>>i)&1)HS0|=((HS&HSi[i])<<(1<<i));
    30             if (!id[HS0])id[HS0]=++t,q.push(HS0);
    31             tr[id[HS]][S]=id[HS0];
    32         }
    33     }
    34     f[1]=1;
    35     for(int i=1;i<=m;i++){
    36         for(int S=0;S<(1<<n);S++){
    37             P[S]=1;
    38             for(int j=0;j<n;j++)P[S]*=((S>>j)&1 ? p[i][j] : 1-p[i][j]);
    39         }
    40         memcpy(g,f,sizeof(f));
    41         memset(f,0,sizeof(f));
    42         for(int HS=1;HS<=t;HS++)
    43             for(int S=0;S<(1<<n);S++)f[tr[HS][S]]+=P[S]*g[HS];
    44     }
    45     for(it=id.begin();it!=id.end();it++){
    46         int mx=0;
    47         for(int S=0;S<(1<<n);S++)
    48             if (((*it).first>>S)&1)mx=max(mx,__builtin_popcount(S));
    49         ans+=mx*f[(*it).second];
    50     }
    51     printf("%.2f\n",ans);
    52     return 0;
    53 } 
    View Code
  • 相关阅读:
    i++与 ++i的 区 别
    css浮动居中实现2
    a MP4Box GUIYamb介绍
    [教程]安装系统解码器 指导教程
    使用AviSynth将高清mov文件导入并重编码为MKV、MP4
    VS2008常用快捷键
    AvsP介绍——非常好用的AviSynth辅助工具
    C/C++语言中Static的作用详述
    [教程]使用Lite MP4 Tool专业制作MP4(AVC)视频格式 指导教程
    Moving Rows in CListCtrl
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16374734.html
Copyright © 2020-2023  润新知