ATC DP O Matching
https://atcoder.jp/contests/dp/tasks/dp_o
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示第i个人时选取的女孩集合为j时的方案数
那么转移方程为 d p [ i ] [ j ] + = d p [ i − 1 ] [ j − ( 1 < < k ) ] dp[i][j] += dp[i-1][j-(1<<k)] dp[i][j]+=dp[i−1][j−(1<<k)] 其中k为能与第j个人配对的女孩
一种合理的转移方式是从小到大枚举集合再枚举当前i,因为[j-(1<<k)]的部分选择的是j的子集,之前已经枚举完了。
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 30;
const int mod = 1e9 + 7;
typedef long long ll;
int mp[N][N];
int dp[(1 << 22)];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> mp[i][j];
}
}
dp[0] = 1;
for (int cur_set = 1; cur_set < (1 << n); ++cur_set) {
int cur_girls = 0;
for (int s = 0; s <= 23; s++) {
if ((cur_set >> s) & 1)cur_girls++;
}
cur_girls--;
//选一个女孩配对
for (int j = 0; j < n; ++j) {
// 当前集合有j并且当前人跟这个人有联系。
if (cur_set & (1 << j) && mp[cur_girls][j]) {
dp[cur_set] = (dp[cur_set] + dp[cur_set ^ (1 << j)]) % mod;
}
}
}
printf("%d\n", dp[(1 << n) - 1]);
return 0;
}