25 盏灯排成一个 5×5 的方形。
每一个灯都有一个开关,游戏者可以改变它的状态。
每一步,游戏者可以改变某一个灯的状态。
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 6 步以内使所有的灯都变亮。
思路:
我们可以发现 :
(1)每个位置只会被点击一次;
(2)若第i行的一个位置上是0,只需要点击第i+1行上的该位置,就可以使第i行的位置为1;
所以,我们可以一行一行看,先确定第一行,然后根据第一行来确定后面四行;
第一行每个位置是0或者1,一共有32种选择,我们可以枚举这32种选择;
用一个二进制数表示:比如6,二进制表示为00110,表示点击这一行第2,3开关(下标从0开始)
然后递推,最后判断最后一行是否都是1,所以的情况取最小值,即答案;
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
const int N=6;
char g[N][N],bb[N][N];
int dx[]={0,1,0,-1,0};
int dy[]={1,0,-1,0,0};
void turn(int x,int y)//点击x,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) continue;
g[a][b]^=1;
}
}
int main()
{
int T;
cin>>T;
while(T--) //多组测试数据
{
int res=10;
for(int i=0;i<5;i++) scanf("%s",bb[i]);
for(int op=0;op<32;op++)
{
int cnt=0;
memcpy(g,bb,sizeof g);
//枚举第一行
for(int j=0;j<5;j++)
{
if((op>>j&1)==0)
{
turn(0,j);
cnt++;
}
}
// 枚举2-5行
for(int i=0;i<4;i++)
{
for(int j=0;j<5;j++)
if(g[i][j]=='0')
{
turn(i+1,j);
cnt++;
}
}
// 检查最后一行
bool flag=true;
for(int i=0;i<5;i++)
if(g[4][i]=='0')
{
flag=false;
break;
}
if(flag) res=min(res,cnt);
}
//如果结果必6大,题目要求输出-1
if(res>6) puts("-1");
else printf("%d\n",res);
}
return 0;
}