题意
问题描述有 N N N名男性和 N N N名女性,编号分别为 1 , 2 , … , N 1,2,…,N 1,2,…,N。
对于每一对 i , j ( 1 ≤ i , j ≤ N ) i,j(1≤i,j≤N) i,j(1≤i,j≤N),男性 i i i 和女性 j j j 的兼容性被表示为整数 a i , j a_{i,j} ai,j 。 如果 $a_{i,j}=1,则男性 i i i 和女性 j j j 兼容;如果 a i , j = 0 a_{i,j} =0 ai,j=0,则它们不兼容。
Taro试图组成 N N N对,每对由一个男性和一个女性组成,二者必须各自属于一对。
求Taro能够组成 N N N对的方式数量,取模 1 0 9 + 7 10^9+7 109+7。
【样例输入】
3
0 1 1
1 0 1
1 1 1
【样例输出】
3
【样例解释】
- ( 1 , 2 ) , ( 2 , 1 ) , ( 3 , 3 ) (1,2),(2,1),(3,3) (1,2),(2,1),(3,3)
- ( 1 , 2 ) , ( 2 , 3 ) , ( 3 , 1 ) (1,2),(2,3),(3,1) (1,2),(2,3),(3,1)
- ( 1 , 3 ) , ( 2 , 1 ) , ( 3 , 2 ) (1,3),(2,1),(3,2) (1,3),(2,1),(3,2)
思路
记 d p i dp_i dpi 表示状态为 i i i 对应的当前已经被配对到的女性,其中:
i = 2 0 a 0 + 2 1 a 1 + … 2 n a n , a i = 0 / 1 i = 2^0a_0 +2^1a_1 + \dots2^na_n,a_i = 0/1 i=20a0+21a1+…2nan,ai=0/1
如果 d p i dp_i dpi 表示 1 1 1 则代表第 i i i 个女生去过。
我们当前要配对的是第
c
n
t
cnt
cnt 个男生,因为已经配对过
∑
i
=
0
n
a
i
\sum_{i=0}^{n}{a_i}
∑i=0nai,所以有当前配对的是第
∑
i
=
0
n
a
i
+
1
\sum_{i=0}^{n}{a_i} + 1
∑i=0nai+1 个。__builtin_popcount(i)
代表
i
i
i 在二进制中一的数量。
枚举当前配对的女生 j j j,再转移即可。
代码
#include<bits/stdc++.h>
#define int long long
const int p = 1000000007;
using namespace std;
int n,a[25][25];
int dp[(1 << 21) + 10],ans = 0;
signed main() {
scanf("%lld",&n);
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= n;j++) {
scanf("%lld",&a[i][j]);
}
}
dp[0] = 1;
for(int i = 0;i < (1 << n);i++) {
int cnt = __builtin_popcount(i) + 1;
for(int j = 1;j <= n;j++) {
if(a[cnt][j] and (i & (1 << (j - 1))) == 0) {
dp[i | (1 << (j - 1))] += dp[i];
dp[i | (1 << (j - 1))] %= p;
}
}
//printf("%lld\n",dp[i]);
}
printf("%lld\n",dp[(1 << n) - 1]);
}