思路
对第一行所有可能的操作情况进行枚举, 后续每一行的操作都由上一行决定, 每一种枚举方案是否达标通过检查最后一行操作完后是否满足要求即可
注意
开关类最优解问题:
1.每个点至多摁一次
2.摁的顺序不影响最终结果
代码
#include <bits/stdc++.h>
using namespace std;
int n;
char st[6][6],backup[6][6]; //多开一位 接收'\0'
int dx[5] = {0,-1,0,1,0},dy[5] = {-1,0,1,0,0}; //方向向量数组
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>4||b<0||b>4) continue; //超出边界 直接忽略
//未超边界 状态取反
st[a][b] ^= 1;
}
}
int main()
{
cin>>n;
while(n--)
{
//读入一组游戏数据
for(int i =0;i < 5;i++) cin>>st[i];
//存储该组游戏的结果
int res = 10;
//备份原始状态
memcpy(backup,st,sizeof(st));
//每组游戏第一行均有2^5=32种操作 对应0~31的二进制表示
for(int op = 0;op < 32;op++)
{
//当前这种操作所对应的步骤数
int step =0;
for(int i = 0;i < 5;i++)
{
//op为1 说明要进行一次翻转
if(op>>i&1)
{
//每翻转一次 步骤数加一
step++;
turn(0,4-i);
}
}
//处理完第一行后 剩下每一行对应的操作由上一行的状态决定
for(int i = 0;i < 4;i++)
{
for(int j = 0;j < 5;j++)
{
//上一行操作完后为暗的地方 下一行同列位置要翻转一次
//上一行操作完后为亮的地方 下一行同列位置无需操作
if(st[i][j] == '0')
{
step++;
turn(i+1,j);
}
}
}
//如上操作完后 前4行一定为全亮 检查最后一行的状态是否满足全亮
bool dark = false;
for(int i = 0;i < 5;i++)
{
if(st[4][i] == '0')
{
dark = true;
break;
}
}
if(!dark) res = min(res,step);
memcpy(st,backup,sizeof(backup));
}
if(res>6) cout<<-1<<endl;
else cout<<res<<endl;
}
return 0;
}