你玩过“拉灯”游戏吗?
25 盏灯排成一个 5×5 的方形。
每一个灯都有一个开关,游戏者可以改变它的状态。
每一步,游戏者可以改变某一个灯的状态。
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。
下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 6 步以内使所有的灯都变亮。
输入格式
第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。
以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。
每组数据描述了一个游戏的初始状态。
各组数据间用一个空行分隔。
输出格式
一共输出 n 行数据,每行有一个小于等于 6 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若 6 步以内无法使所有灯变亮,则输出 −1。
数据范围
0<n≤500
输入样例
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
输出样例
3
2
-1
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
char st1[6][6],st2[6][6];//灯的状态st1,st2,st2是用来备份初始状态
void turn(int x,int y)
{
int dx[5]={0,0,1,0,-1},dy[5]={0,1,0,-1,0};
for(int i=0;i<5;i++)
{
int a=x+dx[i];
int b=y+dy[i];
if(a>=5||a<0||b>=5||b<0)//边界
continue;
st1[a][b]=st1[a][b]^1;//‘0’变‘1’,‘1’变‘0’,因为‘0’ASCII是48(110000),‘1’是49(110001),所以和1异或可互变
}
}
int main()
{
int n;
cin>>n;
while(n--)
{
for(int i=0;i<5;i++)
cin>>st1[i];
//备份数组st2
memcpy(st2,st1,sizeof(st1));
// for(int i=0;i<5;i++)
// {
// for(int j=0;j<5;j++)
// st2[i][j]=st1[i][j];
// }
int res=10;
for(int op=0;op<32;op++)//遍历第一行的所有情况00000~11111
{
int step=0;
for(int i=0;i<5;i++)
{
if(op>>i&1)//如果第一行的二进制某位上是1,则进行开关操作,需要按下去
{
turn(0,i);
step++;
}
}
for(int i=0;i<4;i++)//第2到5行,根据前一行的灯的状态,如果是熄灭状态‘0’,则需要按下去
{
for(int j=0;j<5;j++)
{
if(st1[i][j]=='0')
{
turn(i+1,j);
step++;
}
}
}
int flag=0;
for(int j=0;j<5;j++)//根据最后一行第5行的状态,如果有熄灭状态,则此情况不行
{
if(st1[4][j]=='0')
{
flag=1;
break;
}
}
if(flag==0)
res=min(res,step);
//还原数组st1
memcpy(st1,st2,sizeof(st1));
// for(int i=0;i<5;i++)
// {
// for(int j=0;j<5;j++)
// st1[i][j]=st2[i][j];
// }
}
if(res>6)
cout<<-1<<endl;
else
cout<<res<<endl;
}
return 0;
}