#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 6;
char state[maxn][maxn]; // 存储游戏状态的矩阵,使用char类型方便一次输入一行
char backup[maxn][maxn]; // 用于备份游戏状态
int dx[5] = {-1, 0, 1, 0, 0};
int dy[5] = {0, -1, 0, 1, 0};
// 抽象出单独的函数,用于改变灯的状态
// x, y为转变状态灯的坐标
void turn(int x, int y){
// 通过for循环得到(x, y)及周围四盏灯的坐标
for (int i = 0; i < 5; i++){
int a = x + dx[i];
int b = y + dy[i];
// 判断边界溢出
if(a < 0 || a >= 5 || b < 0|| b >= 5){
// 若此坐标不合法,则继续访问其他坐标
continue;
}
// 若坐标合法则进行状态的转变
state[a][b] ^= 1; // 此处为异或运算,即0-->1 || 1-->0
}
}
int main(){
int n;
scanf("%d", &n);
while(n--){
// 用于记录最小步数
int res = 7;
// 每次直接输入二维数组的一行
for (int i = 0; i < 5; i++){
cin>>state[i];
}
// 首先要保证能够考虑到第一行(通过turn操作后)所有的状态
// 第一行一共5盏灯,共有2^5=32种状态
// 对第一行的每种状态进行递推
// 注:本题影响步数的根本条件即为第一行的状态,因为一旦第一行的状态确定,接下来的递推都是固定的
// 此处的for循环枚举的第一行的操作,即数串op为1的位置表示进行turn操作,为0的地方不进行操作
for(int op = 0; op < 32; op++){
// 将题目给定的初始状态备份
memcpy(backup, state, sizeof state);
int step = 0; // 统计当前方案的步数
for (int i = 0; i < 5; i++){
// 二进制数串op将第i位移至末尾,和1进行与操作,判断第i位是否为1
if (op >> i & 1){
// 若第i位为1则对第一行的第i个位置进行turn操作
step++;
turn(0, i);
}
}
// 1~4行的灯的状态,由下一行管控
// 通过对2~5行进行操作,保证前1~4行全亮
for (int i = 0; i < 4; i++){
for (int j = 0; j < 5; j++){
if (state[i][j] == '0'){
step++;
turn(i+1, j);
}
}
}
bool flag = true;
// 遍历第5行,若此时仍有灯未亮,说明该方案行不通
for (int j = 0; j < 5; j++){
if (state[4][j] == '0'){
flag = false;
}
}
// 如果方案行得通,则比较得出较小步数
if(flag){
res = min(res, step);
}
memcpy(state, backup, sizeof state);
}
// 若得出方案的步数最少仍大于6,则非法
if (res > 6){
res = -1;
}
cout<<res<<endl;
}
return 0;
}
95. 费解的开关
最新推荐文章于 2022-12-10 21:36:16 发布