#include #include using namespace std; typedef long long LL; const int N = 17, BB = 1 << N; int a[N][N]; LL f[BB][N]; /** * 状压dp * f[mask][u],在mask的选手集合里u获胜的次数 * 转移: * 1.把mask拆成两个子集A,B * 2.枚举A,B中的元素,j&k * 3.if (j 胜 k) dp[mask][j] += dp[A][j] * dp[B][k]; * else dp[mask][k] += dp[A][j] * dp[B][k]; */ int main() { // freopen("knockout.in", "r", stdin); // freopen("knockout.out", "w", stdout); for (int i = 0; i < 16; ++i) { for (int j = 0; j < 16; ++j) { scanf("%d", &a[i][j]); } } for (int i = 0; i < 16; ++i) { for (int j = 0; j < i; ++j) { a[i][j] = -a[j][i]; } } for (int i = 0; i < 16; ++i) { f[1 << i][i] = 1; } for (int len = 2; len <= N; len *= 2) { for (int mask = 0; mask < (1 << N); ++mask) { if (__builtin_popcount(mask) != len) continue; for (int A = mask; A; A = (A - 1) & mask) { if (__builtin_popcount(A) != len / 2) continue; int B = mask ^ A; for (int j = 0; j < N; ++j) { if (!(A & (1 << j))) continue; for (int k = 0; k < N; ++k) { if (!(B & (1 << k))) continue; if (a[j][k] == 1) f[mask][j] += f[A][j] * f[B][k]; else f[mask][k] += f[A][j] * f[B][k]; } } } } } for (int i = 0; i < 16; ++i) { printf("%lld\n", f[(1 << 16) - 1][i]); } return 0; }