我终于想出来了
题目描述:
你玩过“拉灯”游戏吗?
2525 盏灯排成一个 5×55×5 的方形。
每一个灯都有一个开关,游戏者可以改变它的状态。
每一步,游戏者可以改变某一个灯的状态。
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字 11 表示一盏开着的灯,用数字 00 表示关着的灯。
下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 66 步以内使所有的灯都变亮。
输入格式
第一行输入正整数 nn,代表数据中共有 nn 个待解决的游戏初始状态。
以下若干行数据分为 nn 组,每组数据有 55 行,每行 55 个字符。
每组数据描述了一个游戏的初始状态。
各组数据间用一个空行分隔。
输出格式
一共输出 nn 行数据,每行有一个小于等于 66 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若 66 步以内无法使所有灯变亮,则输出 −1−1。
数据范围
0<n≤5000<n≤500
输入样例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
输出样例:
3
2
-1
思考了一天都晕了,大概就是,每一行的暗灯,由下一行去点亮,枚举第一行的所有情况,在每种情况下,去操作,判断,得出全点亮的步数,在从所有步数中得到最小值,最优解,
Note
枚举第1行,用二进制按位,应用0和1,表示按与不按,
要记住,返场,恢复现场,memcpy复制副本,
下面是代码啦~,希望遗忘不会不会加速,,,
#include <iostream>
#include <cstdio>
#include <cstring>//memcpy(a,b,sizeof b)
using namespace std;
char g[10][10];
//封装turn函数,就按下去,中(x,y)上下左右的灯都按下去
int dx[5] = { 0,-1,1,0,0 }; //中上下左右
int dy[5] = { 0,0,0,-1,1 };
void turn(int x, int y)
{
for (int i = 0; i < 5; i++)//遍历5个位置
{
int a = x + dx[i];
int b = y + dy[i];
if (a >= 0 && a < 5 && b >= 0 && b < 5)//五个位置合法
{
g[a][b] = ('0' + ('1' - g[a][b]));//转换,'0'->'1';'1'->'0';
//g[a][b]^=1; //也可直接异或,
}
}
}
int work()
{
int ans = 10;
//我们这里枚举第1行所有的32种情况,在每一种情况下,去操作
for (int k = 0; k < 1 << 5; k++)
{
char backup[10][10];
memcpy(backup, g, sizeof g); //备份一份初始的,便后面恢复现场
int count = 0;//计按几次
//第一行的按法(1代表按,0不按)
for (int j = 0; j < 5; j++)
{
if (k >> j & 1) //用二进制数,来模拟按与不按
{ //如第一种情况k==1;即00001,在右移运算符操作后
//00001>>1 之后为00000,接着&1==0,所以第二个位置不按
//同理,00001>>0之后为00001,第一个位置按
count++; //k==3时,00011,表示第1,2个位置按
turn(0, j);
}
}
//按照第一行的0,去依次对234行操作
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
if (g[i][j] == '0')
{
count++;
turn(i + 1, j); //如果这盏灯灭这,就按对应的下一行的灯
}
}
}
bool is_successful = true;
//判断最后一行,是否全为开
for (int j = 0; j < 5; j++)
{
if (g[4][j] == '0')
{
is_successful = false;
break;
}
}
if(is_successful) ans = min(ans, count); //32种情况中,有很多解法,这时,就需要ans来,
//把最小步数存一下,就能找到最优解
memcpy(g, backup, sizeof g);
}
if (ans > 6) return -1;
else return ans;
}
int main()
{
int t;
cin >> t;
while (t--)
{
for (int i = 0; i < 5; i++) //一次输入一行字符串,
cin >> g[i];
cout << work() << endl;
}
}
一个平平常常的日子,细蒙蒙的雨丝夹着一星半点的雪花,正纷纷淋淋地向大地飘洒着。时令已快到惊蛰,雪当然再不会存留,往往还没等落地,就已经消失得无影无踪了。
《平凡的世界》
2022年2月7日17:32:34