我们很容易想到两点
- 每一个位置顶多只会操作一次(因为如果操作两次的话,相当于不操作,必然是不满足最优解)
- 在一套方案中,操作的顺序无关紧要(因为每个按钮是0还是1,只取决于它或它周围的按钮被按下的次数)
我们假定上一行已经不能改变了
那么如果上一行中存在’0’,我们想让它变成’1’,就需要按下一行的按钮;
即若第 i i i行存在’0’,我们现在固定(不按按钮)第 i i i行,要想让这些’0’变成’1’,只能去按 i + 1 i+1 i+1行的按钮;
同理若 i + 1 i+1 i+1行是固定的,要操作只能去操作 i + 2 i+2 i+2行,以此类推;
那么我们想要获得最优解,只需要枚举第一行的所有按法,然后依次递推给下一行,就可以求出所有的方案,取min则得最优解;
Code
#include <iostream>
#include <cstring>
using namespace std;
const int N = 10;
int dx[5] = {0,-1,1,0,0};
int dy[5] = {0,0,0,1,-1};
char str[N][N];
char gstr[N][N];
void change(int x,int y){
for(int k=0;k<5;++k){
int i = x+dx[k];
int j = y+dy[k];
if(i<1||i>5||j<1||j>5) continue;
//'0' -> '1' 或 '1' -> '0'
str[i][j]^=1;
}
}
void solve(){
//枚举第一行的按法
int ans = 7;//>6即可
for(int i=0;i<(1<<5);++i){
memcpy(str,gstr,sizeof(str));
int count = 0;
for(int j=0;j<5;++j){
if(i>>j & 1){
change(1,j+1);
++count;
}
}
for(int h=2;h<=5;++h){
for(int l=1;l<=5;++l){
if(str[h-1][l] == '1') continue;
//为0
change(h,l);
++count;
}
}
bool flag = true;
//现在保证除了最后一行的灯都是全部亮的
for(int l=1;l<=5;++l){
if(str[5][l] == '0'){
flag = false;
break;
}
}
//只有全部是亮的 并且这个解更加优秀 那么更新ans
if(flag){
ans = min(ans,count);
}
}
ans=ans<=6?ans:-1;
cout << ans << '\n';
}
int main(){
int t;
cin >> t;
while(t--){
for(int i=1;i<=5;++i){
cin >> (gstr[i]+1);
}
solve();
}
return 0;
}