1. 程式人生 > >Codechef:Expected Maximum Matching/MATCH(Hall定理)

Codechef:Expected Maximum Matching/MATCH(Hall定理)

傳送門

題解:
利用Hall定理來判斷每個左邊集合是否滿足有完美匹配。

這樣是 O ( 2 2 n )

O(2^{2^n}) 的,不過有用狀態很少。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned int uint;

int n,m,lim,y,tot;
double p[6][105];
uint bin[32];
vector <int> val;
vector <uint> nxt[32];
vector <double> f[2];
map <uint,int> id;
inline void dfs(int sta,uint sum) { if(!sta) { id[sum]=tot++; int mx=0; for(int i=1;i<lim;i++) if(sum&bin[i]) mx=max(mx,__builtin_popcount(i)); val.push_back(mx); for(int i=0;i<lim;i++) { uint now=sum; for(int j=0;j<n;j++) if(i&bin[j]) for(int k=1;k<lim;k++) if(
(k&bin[j]) && (sum&bin[k^bin[j]])) now|=bin[k]; nxt[i].push_back(now); } return; } if(!(sum&bin[sta])) dfs(sta-1,sum); if(!(sum&bin[sta])) for(int i=sta;i;i=(i-1)&sta) sum|=bin[i]; dfs(sta-1,sum); } inline void trans(int pos,int sta,double v,int o) { if(pos==n) { for(int j=0;j<tot;j++) f[y^1][nxt[sta][j]]+=f[y][j]*v; return; } trans(pos+1,sta,v*(1-p[pos][o]),o); trans(pos+1,sta|bin[pos],v*p[pos][o],o); } int main() { scanf("%d%d",&n,&m); lim=1<<n; for(int i=0;i<lim;i++) bin[i]=1ull<<i; dfs(lim-1,1); for(int i=0;i<lim;i++) for(int j=0;j<nxt[i].size();j++) nxt[i][j]=id[nxt[i][j]]; for(int i=0;i<=1;i++) f[i].resize(tot); f[y][id[1]]=1; for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%lf",&p[i][j]); for(int i=0;i<m;i++) { for(int j=0;j<f[y].size();j++) f[y^1][j]=0; trans(0,0,1,i), y^=1; } double ans=0; for(int i=0;i<tot;i++) ans+=f[y][i]*val[i]; printf("%.6f\n",ans); }