由于人很少,我们可以用longlong进行位运算记录 每个人匹配的状态,根据hall定理我们可以知道很多状态都是不成立的,所以我们先预处理出每种状态之间的关系,把位数太大的数进行hash,然后就跑压状dp了。
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define n 105
#define m 4005
#define DB double
#define u64 unsigned long long
#define For(i,a,b) for(int i=a;i<=b;i++)
u64 G[7],Q[m];
DB P[7][n],F[n][m];
int N,M,U,T,cnt[65],A[m][65];
map<u64,int>D;
int main()
{
scanf("%d%d",&N,&M);
U=(1<<N)-1;
For(i,1,N)
For(j,1,M)
scanf("%lf",&P[i][j]);
D[1]=Q[1]=T=1;
for (int l=0,r=1;l<r;)
{
u64 now=Q[++l];
For(i,1,N)
{
G[i]=now;
For(j,0,U)
if((1ll<<j)&now)
G[i]|=1ll<<(j|(1<<i-1));
}
For(i,0,U)
{
u64 t=now;
For(j,1,N)
if((1<<j-1)&i) t|=G[j];
if (!D.count(t))
Q[++r]=t,D[t]=++T;
A[l][i]=D[t];
}
}
F[0][1]=1;
For(i,1,M)
For(j,1,T)
if(F[i-1][j])
For(k,0,U)
{
DB p=1;
For(t,1,N)
((1<<t-1)&k)?p*=P[t][i]:p*=(1-P[t][i]);
F[i][A[j][k]]+=p*F[i-1][j];
}
DB Ans=0;
For(i,1,63)
cnt[i]=cnt[i>>1]+(i&1);
For(i,1,T)
if (F[M][i])
{
int t=0;
For(j,0,U)
if((1ll<<j)&Q[i])
t=max(t,cnt[j]);
Ans+=t*F[M][i];
}
printf("%.2lf\n",Ans);
return 0;
}