题目:
你玩过“拉灯”游戏吗?
25 盏灯排成一个 5×5 的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。
下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 66 步以内使所有的灯都变亮。
输入格式:
第一行输入正整数 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<iostream>
#include<cstring>
using namespace std;
const int INF=100000000000;
char g[10][10]; //定义全局变量数组
int t;//定义数组数量
int dx[5]={0,-1,0,1,0};
int dy[5]={0,0,1,0,-1};//两个数组来定义中上右下左的坐标
void turn(int x,int y){//本函数用于调整灯的亮灭情况
for(int i=0;i<5;i++){
int a=x+dx[i];
int b=y+dy[i];
if(a>=0&&a<5&&b>=0&&b<5)//判断上下左右是否存在
g[a][b]^=1;//通过异或来改变当前位置是0/1
}
}
int work(){
int ant=INF;//设置一个固定量
for(int k=0;k<32;k++){//枚举所有的情况
int res=0;//次数
char cp_g[10][10];
memcpy(cp_g,g,sizeof g);//存储数组
for(int i=0;i<5;i++){
if(k>>i&1){
res++;
turn(0,i);
}
}
for(int i=0;i<4;i++){//通过上一行来确定下一行
for(int j=0;j<5;j++){
if(g[i][j]=='0'){
res++;
turn(i+1,j);
}
}
}
bool is_success=true;//判断最后一行是否全部都亮着
for(int i=0;i<5;i++){
if(g[4][i]=='0'){
is_success=false;
break;
}
}
if(is_success) ant=min(ant,res); //寻找最少res次数
memcpy(g,cp_g,sizeof cp_g);//重置数组,以便进入下一次循环
}
if(ant>6) ant=-1;//如果运行步数高于6,就输出-1
return ant;
}
int main(){
cin>>t;
while(t--){//while循环输入数组
for(int i=0;i<5;i++) cin>>g[i];//输入
cout<<work()<<endl;//work()函数修改数组
}
return 0;
}
费解的开关看懂的想更深入学习可以参考下列我的另一篇博客: