[枚举,思维]费解的开关
这道题体现了一个重要的思路:当面对一个情况复杂、不知从何下手的问题,而且进行若干操作的结果与它们的顺序无关时,不妨考虑按一定顺序操作,比如一行一行地考虑。
首先,显然每个位置至多操作一次。所以不难得到一个枚举\(2^{25}\)种情况的算法(逃)
但如果我们考虑一行一行地进行处理:
那么当我们固定(不再修改)\(i-1\)行时,有且仅有一种对第\(i\)行的操作,使得第\(i-1\)行全为1:只改变上一行关着的灯下面的灯
也就是说,对第1行进行某种操作后,有且只有一种方案,使前4行全为1。
因此我们只需要枚举第1行的所有可能操作(32种),判断经过上述操作后,第5行是否恰为11111即可
#include <iostream>
using namespace std;
int a[5][5], b[5][5];
int t[32][5];
void init() {
for (int i = 0; i < 32; i++) {
for (int j = 0; j < 5; j++) {
t[i][j] = (i >> (4 - j)) & 1;
}
}
}
void input() {
string s;
for (int i = 0; i < 5; i++) {
cin >> s;
for (int j = 0; j < 5; j++) a[i][j] = s[j] - '0', b[i][j] = a[i][j];
}
}
void resume() {
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++) a[i][j] = b[i][j];
}
bool in(int x) { return x >= 0 && x < 5; }
void change(int x, int y) {
if (in(x) && in(y)) a[x][y] ^= 1;
if (in(x + 1) && in(y)) a[x + 1][y] ^= 1;
if (in(x - 1) && in(y)) a[x - 1][y] ^= 1;
if (in(x) && in(y + 1)) a[x][y + 1] ^= 1;
if (in(x) && in(y - 1)) a[x][y - 1] ^= 1;
}
int solve(int t[]) {
int cnt = 0;
for (int i = 0; i < 5; i++)
if (t[i]) change(0, i), cnt++;
for (int i = 1; i < 5; i++)
for (int j = 0; j < 5; j++)
if (!a[i - 1][j]) change(i, j), cnt++;
if (cnt > 6) {
resume();
return 7;
}
for (int i = 0; i < 5; i++) {
if (a[4][i] != 1) {
resume();
return 7;
}
}
return cnt;
}
int main() {
init();
int T;
cin >> T;
while (T--) {
input();
int ans = 7;
for (int i = 0; i < 32; i++) {
ans = min(ans, solve(t[i]));
}
ans <= 6 ? cout << ans << endl : cout << -1 << endl;
}
return 0;
}