[bzoj2891]匹配难题

对于\(S\subseteq \{T\mid T\subseteq [1,A]\}\),定义\(f_{i,S}\)表示左侧(对右侧前\(i\)个点)存在完美匹配的集合为\(S\)的概率

\(f_{i-1,S}\)转移到\(f_{i,S'}\)时枚举\(i\)的出边\(O\subseteq [1,n]\),则\(S'=S\cup \{T\mid \exists j\in O\cap T,T\backslash\{j\}\in S\}\)

爆搜可得(当\(A=6\)时)可能的\(S\)仅有\(3762\)种,时间复杂度为\(O(3762\cdot 2^{A}B)\)

#include<bits/stdc++.h>
using namespace std;
#define N 105
#define M 40000
#define ull unsigned long long
int n,m,t;double ans,p[N][6],P[1<<6],g[M],f[M];
ull HSi[6],tr[M][1<<6];queue<ull>q;
map<ull,int>id;map<ull,int>::iterator it;
int main(){
   scanf("%d%d",&n,&m);
   if (n<=m){
       for(int i=0;i<n;i++)
           for(int j=1;j<=m;j++)scanf("%lf",&p[j][i]);
   }
   else{
       swap(n,m);
       for(int j=1;j<=m;j++)
           for(int i=0;i<n;i++)scanf("%lf",&p[j][i]);
   }
   for(int i=0;i<n;i++)
       for(int S=0;S<(1<<n);S++)
           if ((S>>i)&1^1)HSi[i]|=((ull)1<<S);
   t=id[1]=1,q.push(1);
   while (!q.empty()){
       ull HS=q.front();q.pop();
       for(int S=0;S<(1<<n);S++){
           ull HS0=HS;
           for(int i=0;i<n;i++)
               if ((S>>i)&1)HS0|=((HS&HSi[i])<<(1<<i));
           if (!id[HS0])id[HS0]=++t,q.push(HS0);
           tr[id[HS]][S]=id[HS0];
       }
   }
   f[1]=1;
   for(int i=1;i<=m;i++){
       for(int S=0;S<(1<<n);S++){
           P[S]=1;
           for(int j=0;j<n;j++)P[S]*=((S>>j)&1 ? p[i][j] : 1-p[i][j]);
       }
       memcpy(g,f,sizeof(f));
       memset(f,0,sizeof(f));
       for(int HS=1;HS<=t;HS++)
           for(int S=0;S<(1<<n);S++)f[tr[HS][S]]+=P[S]*g[HS];
   }
   for(it=id.begin();it!=id.end();it++){
       int mx=0;
       for(int S=0;S<(1<<n);S++)
           if (((*it).first>>S)&1)mx=max(mx,__builtin_popcount(S));
       ans+=mx*f[(*it).second];
   }
   printf("%.2f\n",ans);
   return 0;
}
posted @ 2022-06-14 15:04  PYWBKTDA  阅读(87)  评论(0编辑  收藏  举报