[BZOJ2560] 串珠子 [子集列舉][狀態壓縮][dp][容斥]
阿新 • • 發佈:2018-11-12
注意列舉子集計算
的時候要先去掉一個點防止重複計數。
那麼讓能隨意連邊的一邊不包含這個點,不隨意連邊的一邊包含這個點(不能反過來!)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include <cmath>
#include<set>
#include<ctime>
using namespace std;
const long long mod = 1000000007;
int n;
long long c[20][20];
long long F[66666];
long long G[66666];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf("%lld", &c[i] [j]);
}
}
int up = (1 << n) - 1;
for (int i = 1; i <= up; ++i) {
G[i] = 1;
for (int j = 1; j <= n; ++j) {
if (!(i & 1 << j - 1)) continue;
for (int k = j + 1; k <= n; ++k) { // * from (j+1)
if (!(i & 1 << k - 1)) continue;
G[i] *= c[j][k] + 1;
G[i] %= mod;
}
}
F[i] = G[i];
int upup = i & (i - 1);
for (int j = upup; j; j = upup & (j - 1)) {
F[i] = (F[i] - G[j] * F[i ^ j] % mod + mod) % mod;
}
}
printf("%lld", F[up]);
return 0;
}