题目
N 个男孩,N 个女孩,男孩和女孩可能是朋友,也可能不是朋友。现在要组成N 对舞伴,要求每对舞
伴都是一男一女,且他们是朋友。
统计不同配对方案的数量,因为结果很大,所以只要求除以M 的余数。
N<=20
分析
因为N只有20,所以直接想到状压dp
设f[i,s]表示做完前i个男生,女生被匹配的状态为s的方案数
枚举i,s接着枚举第i个男生选了哪个女生,然后转移
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
const int maxn=22;
int f[maxn][1<<(maxn-1)];
long long n,m;
int a[maxn];
int b[maxn][1<<(maxn-4)];
int main()
{
freopen("perm.in","r",stdin);
freopen("perm.out","w",stdout);
cin>>n>>m;
for (int i=1;i<=n;i++)
{
int x=0;
for (int j=1;j<=n;j++)
{
int y;
scanf("%d",&y);
x=x*2+y;
}
a[i]=x;
}
for (int j=0;j<=(1<<n)-1;j++)
{
int x=j,y,k=0;
while (x)
{
y=x%2;
if (y) k++;
x/=2;
}
b[k][++b[k][0]]=j;
}
f[0][0]=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=b[i][0];j++)
{
int x=b[i][j]&a[i],y,k=0;
while (x)
{
k++; y=x%2;
if (y) f[i][b[i][j]]=((f[i][b[i][j]]%m)+f[i-1][b[i][j]^(1<<(k-1))])%m;
x/=2;
}
}
}
printf("%d",f[n][(1<<n)-1]%m);
fclose(stdin);
fclose(stdout);
}