思路
1.最优解一定是每个灯最多按一次。
2.从最终效果看,按灯的顺序是无所谓的
接下来我们只要思考怎么不重不漏地枚举所有情况就好
因为按灯的顺序无所谓,所以我们尝试直接枚举第一行被按的情况。
第一行形式都被确定了之后,为了让第一行全部的灯都亮,第二行的怎么按都已经是定数了.........以此类推,第五行的按法会被第四行决定。
由第一行的情况,一直推导出第五行的按法。
但是这种”成全上一行“的做法,无法保证第五行的灯全亮。
所以最后要验证第五行。如果第五行也全亮,就说明这个按法是可行的。
最后根据步数输出结果即可。
AC code
#include<iostream>
#include <cstring>
using namespace std;
int light[10][10],n;
int dx[] = {0,-1,0,1,0},dy[]={0,0,1,0,-1};
//debug用
void print()
{
cout<<endl;
for(int i=0;i<5;i++){
for(int j=0;j<5;j++)
cout<<light[i][j]<<" ";
cout<<endl;
}
cout<<endl;
}
//传入行列
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)
{
light[a][b]=1-light[a][b];
}
}
}
int work()
{
int tmp[10][10],res=99999;
memcpy(tmp,light,sizeof light);
//枚举第一行都按法
for(int i = 0 ; i <(1<<5) ; i++)
{
int count = 0;
//按下第一行
for(int k = 0 ; k < 5 ; k ++)
if(i>>k&1)
{
count++;
turn(0,k);
}
//确保前四行成立
for(int j = 0 ; j < 4; j++)
{
for(int k = 0 ; k <5; k++)
{
if(light[j][k]==0)
{
count++;
turn(j+1,k);
}
}
}
//检查
for(int j=0;j<5;j++)
for(int k=0;k<5;k++)
{
//失败
if(light[j][k]==0)count = 99999;
}
res = min(res,count);
memcpy(light,tmp,sizeof tmp);
}
if(res>6) return -1;
else return res;
}
int main()
{
cin>>n;
while(n--)
{
//贼坑 输入是一串数字 不是一个个01数字
for(int i=0;i<5;i++)
{
string s;
cin>>s;
for(int j=0;j<5;j++)
light[i][j] = s[j]-'0';
}
// print();
cout<<work()<<endl;
}
return 0;
}