目录
题目-开关问题

问题分析
n n n个开关相当于 n n n个未知数, 假设对 1 1 1号灯的初始状态是 0 0 0, 目标状态是 1 1 1, 假设有 x 2 x_2 x2和 x 3 x_3 x3开关会对其产生影响, 那么有方程 x 2 ⊕ x 3 = 1 x_2 \oplus x_3 = 1 x2⊕x3=1
相当于是 n n n个方程 n n n个未知数, 高斯消元求解异或线性方程组 , 基础数学算法中有对应的代码
但是该问题求的是方案数, 最终如果有解, 每一个自由变量 只有两种选法
假设自由元 的数量是 k k k, 那么方案数等于 2 k 2 ^ k 2k
算法步骤
- 构建线性异或方程组
- 高斯消元
- 计算自由元的个数, 假设是 0 0 0, 实际只有一种方法
- 如果不是 1 1 1, 最终结果就是 2 k 2 ^ k 2k
代码实现
在多组测试用例的情况下, cin和printf不要混用!!!
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 35;
int T;
int n, f[N][N];
int gauss() {
int r, c;
for (r = c = 0; c < n; ++c) {
int idx = r;
for (int i = r; i < n; ++i) {
if (f[i][c]) {
idx = i;
break;
}
}
if (!f[idx][c]) continue;
for (int i = c; i <= n; ++i) swap(f[r][i], f[idx][i]);
for (int i = r + 1; i < n; ++i) {
if (!f[i][c]) continue;
for (int j = n; j >= c; --j) {
f[i][j] ^= f[r][j] & f[i][c];
}
}
r++;
}
int ans = 1;
if (r <= n) {
for (int i = r; i < n; ++i) {
if (f[i][n]) return -1;
ans *= 2;
}
}
return ans;
}
void solve() {
cin >> n;
memset(f, 0, sizeof f);
for (int i = 0; i < n; ++i) cin >> f[i][n];
for (int i = 0; i < n; ++i) {
int val;
cin >> val;
f[i][n] ^= val;
f[i][i] = 1;
}
int a, b;
while (cin >> a >> b, a || b) {
f[b - 1][a - 1] = 1;
}
int ans = gauss();
if (ans == -1) printf("Oh,it's impossible~!!\n");
else printf("%d\n", ans);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> T;
while (T--) solve();
return 0;
}