费解的开关问题

题目如下:

你玩过"拉灯"游戏吗?

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 行数据,每行有一个小于等于 66 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。

对于某一个游戏初始状态,若 66 步以内无法使所有灯变亮,则输出 −1。

数据范围

0<n≤500

输入样例:

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

输出样例:

3
2
-1

代码如下:

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;

const int INF = INT_MAX;

vector<vector<int>> g(5, vector<int>(5));
vector<vector<int>> tmp(5, vector<int>(5));

void turn(int x, int y) {
    int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};
    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)
            tmp[a][b] ^= 1;
    }
}

int check() {
    int res = INF;
    for (int i = 0; i < 32; i++) {
        tmp = g;
        int cnt = 0;
        
        for (int j = 0; j < 5; j++) {
            if (i >> j & 1) {
                turn(0, j);
                cnt++;
            }
        }
        
        for (int j = 0; j < 4; j++) {
            for (int k = 0; k < 5; k++) {
                if (tmp[j][k] == 0) {
                    turn(j + 1, k);
                    cnt++;
                }
            }
        }

        bool allone = true;
        for(int j = 0; j < 5; j++)
            if(tmp[4][j] == 0)
                allone = false;

        if (allone)
            res = min(res, cnt);

    }

    if (res > 6)
        return -1;

    return res;
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                char c;
                cin >> c;
                g[i][j] = c - '0';
            }
        }
        int steps = check();
        cout << steps << endl;
    }
    return 0;
}

思路:

递推:确定上一行状态,就能推出下一行状态,因此需要确定第一行状态

枚举第一行状态,一共32中情况,用变量 cnt 记录每种情况需要改变的次数,代码中用 i 的二进制表示第一行的状态,确定第一行状态后,将第一行不是 1 的位置的下一格进行改变(turn函数),最后查看最后一行是否都为 1 ,更新最终结果到 res 中

相关推荐
ragnwang12 分钟前
C++ Eigen常见的高级用法 [学习笔记]
c++·笔记·学习
yuanManGan36 分钟前
数据结构漫游记:静态链表的实现(CPP)
数据结构·链表
火星机器人life2 小时前
基于ceres优化的3d激光雷达开源算法
算法·3d
虽千万人 吾往矣2 小时前
golang LeetCode 热题 100(动态规划)-更新中
算法·leetcode·动态规划
arnold663 小时前
华为OD E卷(100分)34-转盘寿司
算法·华为od
ZZTC3 小时前
Floyd算法及其扩展应用
算法
lqqjuly3 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
lshzdq3 小时前
【机器人】机械臂轨迹和转矩控制对比
人工智能·算法·机器人
冰红茶兑滴水4 小时前
云备份项目--工具类编写
linux·c++
刘好念4 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl