解题报告 『费解的开关(递推 + 位运算)』
这题讲一下第一行的枚举就可以了。
第一行枚举的k的第j位如果是1,是指第一行的这一位应该被切换状态(开或关),与初始状态无关(实际上,遇1切换和遇0切换是一样的)。
那么就直接放代码了。
代码实现如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (register int i = (a); i <= (b); i++) const int inf = 0x3f3f3f3f; int T; int dx[5] = {0, 0, 0, -1, 1}, dy[5] = {0, -1, 1, 0, 0}; char lig[10][10]; int MIN(int a, int b) {return a < b ? a : b;} void turn(int x, int y) { rep(i, 0, 4) { int a = x + dx[i], b = y + dy[i]; if (a >= 0 && a <= 4 && b >= 0 && b <= 4) lig[a][b] ^= 1; } } int work() { int ans = inf; rep(k, 0, (1 << 5) - 1) { int res = 0; char back_up[10][10]; memcpy(back_up, lig, sizeof(back_up)); rep(j, 0, 4) { if (k >> j & 1) { res++; turn(0, j); } } rep(i, 0, 3) rep(j, 0, 4) if (lig[i][j] == '0') { res++; turn(i + 1, j); } int flag = 1; rep(j, 0, 4) if (lig[4][j] == '0') { flag = 0; break; } if (flag) ans = MIN(ans, res); memcpy(lig, back_up, sizeof(lig)); } if (ans > 6) return -1; return ans; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); cin >> T; while (T--) { rep(i, 0, 4) rep(j, 0, 4) cin >> lig[i][j]; cout << work() << endl; } return 0; }