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
Solution
n才20,很明显的状压嘛
设f[i,s]表示做完前i个男生,女生被匹配的状态为s的方案数
枚举i,s接着枚举第i个男生选了哪个女生,然后转移
但是注意,状态s中1的数量只能是i,所以要注意在这里进行优化时间,否则会超时
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 25
#define ll long long
using namespace std;
int a[N][N],e[21],n,ks[N],en[N];
struct node{
int x,y;
}k[1048576];
ll mo,f[N][1048576];
bool cnt(node x,node y){return x.y<y.y;}
int main()
{
freopen("perm.in","r",stdin);
freopen("perm.out","w",stdout);
e[0]=1;fo(i,1,20) e[i]=e[i-1]*2;
fo(s,1,e[20]-1)
{
k[s].x=s;fo(j,1,20) if((s & e[j-1])!=0) k[s].y++;
}
sort(k+1,k+1048576,cnt);
fo(s,1,e[20]-1) if(k[s].y!=k[s-1].y) ks[k[s].y]=s,en[k[s].y-1]=s-1;
en[20]=ks[20];
scanf("%d %lld",&n,&mo);
fo(i,1,n) fo(j,1,n) scanf("%d",&a[i][j]);
f[0][0]=1;
fo(i,1,n)
{
fo(l,ks[i],en[i])
{
int s=k[l].x;
fo(j,1,n)
if(a[i][j])
{
if((s & e[j-1])!=0)
f[i][s]=(f[i][s]+f[i-1][s-e[j-1]])%mo;
}
}
}
printf("%lld\n",f[n][e[n]-1]);
}