当第一行确定后,后面的开关按钮方案就已经确定。
假如要调整第g[i],[j],只需要按下g[i+1],[j];(十字型)
但是题目给的第一行可能不是最简形式,我们先调整第一行的状态,使问题矩阵变换成多种情况。以此实验最优解。
第一行一共有2^5 种调整方法。
#include<iostream>
#include <cstring>
#include<string>
using namespace std;
const int INF=10;
char g[5][5];//存储初始灯状态
//按下第(x,y)位置后,二维数组的状态变化
void turn(int x,int y)
{
//1^1 = 0,0^1=1
g[x][y]= g[x][y]^1;//中心点
if(x>0)
{
g[x-1][y]=g[x-1][y]^1;//上侧
}
if(x<4)
{
g[x+1][y]=g[x+1][y]^1;//下侧
}
if(y>0)
{
g[x][y-1] = g[x][y-1]^1;//左侧
}
if(y<4)
{
g[x][y+1] = g[x][y+1]^1;//右侧
}
}
int work()
{
int ans=0;
int ret=10;
bool success=true;
char back[5][5];
memcpy(back,g,sizeof(g));//备份
for(int k=0;k<1<<5;k++)//第一行调整,每个灯可以按下或者不按,有1<<5次
{
memcpy(g,back,sizeof(g));//还原备份
ans=0;
//调整第一行
for(int j=0;j<5;j++)
{
if(k>>j&1)
{
ans++;
turn(0,j);
}
}
//第一行确定后分别调整2,3,4,5行
for(int i=0;i<4;i++)
{
for(int j=0;j<5;j++)
{
if(g[i][j]=='0')//第i行第j个灯是灭的,用第i+1,j按钮调整
{
ans++;
turn(i+1,j);
}
}
}
//判断第5行是否有灭的灯,前四行一定调整成功了
success=true;
for(int i=0;i<5;i++)
{
if(g[4][i]!='1')
{
success=false;
break;
}
}
if(success==true) ret=min(ret,ans);
}
//最少调整次数超过6次,失败
if(ret>6) ret=-1;
return ret;
}
int main()
{
int n;
cin>>n;
while(n--)
{
for(int i=0;i<5;i++) cin>>g[i];
cout<<work()<<endl;
}
return 0;
}