Description
N 个男孩,N 个女孩,男孩和女孩可能是朋友,也可能不是朋友。现在要组成N 对舞伴,要求每对舞
伴都是一男一女,且他们是朋友。
统计不同配对方案的数量,因为结果很大,所以只要求除以M 的余数。
Input
第1 行,2 个整数N,M。接下来N 行,每行N 个整数Aij,表示第i 个男孩和第j 个女孩的关系。如果他们是朋友,则Aij = 1,否则Aij = 0。
Output
1 个整数,表示所求的值。
Sample Input
3 1000000000
1 1 1
1 1 1
1 1 1
Sample Output
6
Data Constraint
• 对于50% 的数据,N <= 9;
• 对于100% 的数据,1 <= N <= 20, 1 <= M <= 10^9; 0 <= Aij <= 1。
思路
状压DP
不难看出,因为他们只有选和不选,所以情况有2^40,会炸。
但是,我们可以只枚举男生,女生就只有2^20,可以过。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[22][22],e[22],n,b[22],c[22];
struct node
{
int x,y;
}k[1048576];
long long m,f[22][1048576];
bool cmp(node x,node y){return x.y<y.y;}
int main()
{
// freopen("perm.in","r",stdin);
// freopen("perm.out","w",stdout);
e[0]=1;
for(int i=1; i<=20; i++)
{
e[i]=e[i-1]*2;
}
for(int i=1; i<=e[20]-1; i++)
{
k[i].x=i;
for(int j=1; j<=20; j++)if((i&e[j-1])!=0) k[i].y++;
}
sort(k+1,k+1048576,cmp);
for(int i=1; i<=e[20]-1; i++) if(k[i].y!=k[i-1].y)
{
b[k[i].y]=i;
c[k[i].y-1]=i-1;
}
c[20]=b[20];
scanf("%d %lld",&n,&m);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) scanf("%d",&a[i][j]);
f[0][0]=1;
for(int i=1; i<=n; i++)
{
for(int j=b[i]; j<=c[i]; j++)
{
int s=k[j].x;
for(int k=1; k<=n; k++)
if(a[i][k])
{
if((s&e[k-1])!=0)
f[i][s]=(f[i][s]+f[i-1][s-e[k-1]])%m;
}
}
}
printf("%lld\n",f[n][e[n]-1]);
}