注意枚举子集计算
F
i
\frak{F_i}
Fi的时候要先去掉一个点防止重复计数。
那么让能随意连边的一边不包含这个点,不随意连边的一边包含这个点(不能反过来!)
#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;
}