费解的开关
题目连接
https://www.acwing.com/problem/content/97/
题目描述
输入输出说明
思路
根据数据范围,我们直接暴力枚举搜索结果
发现这道题用递推
的话,若是第一行已经确定不能按,那么想要改变状态只能按第i+1
行,如此,
若是一直下去,到最后一行的时候,那么前面的行数必然已经全满足
,且最后一行不能动,故我们只需判断最后一行的状态即可,那么:
对于此题,我们可以首先枚举第一行的各种状态,比如对每个位置选择按(1) 或者 不按(0),5个位置那么对应
2
5
=
32
2^5 = 32
25=32种选择,然后进行相应操作即可,具体代码及注释如下:
AC代码
//发现这道题用递推的话,若是第一行已经确定不能按,那么想要改变状态只能按第i+1行,如此,
//可以枚举第一行的状态,5个位置那么就是32终状态,然后判断最后一行是否为全满足
#include <iostream>
#include <cstring>
using namespace std;
const int N = 6;
char g[N][N], backup[N][N];
int dx[5] = {0, -1, 0, 1, 0}, dy[5] = {0, 0, 1, 0, -1}; //中、左、上、右、下
void turn(int x, int y) { //对相应坐标数进行操作
for(int i = 0; i < 5; i++) {
int a = x + dx[i], b = y + dy[i];
if(a >= 0 && a < 5 && b >= 0 && b < 5)
g[a][b] ^= 1;
}
}
int main() {
int T;
cin >> T;
while(T --) {
for(int i = 0; i < 5; i++) cin >> g[i];
//进行第一行的32种按法的遍历
int res = 0x3f3f3f3f;
for(int op = 0; op < 1 << 5; op++) { //5位分别对应0(不按)或 1(按)
//数据备份下,反复用
memcpy(backup, g, sizeof backup);
//首先遍历第一行分析是否要按
int step = 0; //操作步数
for(int i = 0; i < 5; i++) {
if(op >> i & 1) { //若为1表示要按
step++;
turn(0, i);
}
}
//第一行的状态初始完成后,进行前四行的操作遍历
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 5; j++) {
if(g[i][j] == '0') { //需要变亮,则操作下一行点亮
step++;
turn(i + 1, j);
}
}
}
//现在前四行的操作已经完成全点亮,第五行不能再操作,操作会影响前四行,于是直接判断第五行状态
bool dark = false;
for(int i = 0; i < 5; i++) {
if(g[4][i] == '0')
dark = true;
}
if(!dark) res = min(res, step);
memcpy(g, backup, sizeof g);
}
if(res > 6) res = -1;
cout << res << endl;
}
return 0;
}