费解的开关问题

题目如下:

你玩过"拉灯"游戏吗?

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 中

相关推荐
GuWenyue1 小时前
传统Agent工具两大痛点!300行代码落地MCP跨语言工具,彻底解耦LLM与工具
前端·人工智能·算法
同勉共进2 小时前
记一例 vibe coding + gcc bug 导致的线程池死锁问题
c++·线程池·gcc·死锁·vibe coding
我叫洋洋2 小时前
C ++ [ hello world ]
c语言·c++·算法
奋发向前wcx3 小时前
y1,y2总复习笔记5 2026.7.19
数据结构·笔记·算法
王维同学6 小时前
[自学][Windows C++]RunOnceEx 注册表分组键的安全遍历
c++·windows·安全·开源
战族狼魂7 小时前
高频面试题精选:分治与AI Agent架构
人工智能·算法·大模型·大语言模型
李剑一7 小时前
你用过网易的将军令嘛?它底层实现账号保护的原理相当简单粗暴
算法
Scott9999HH7 小时前
告别流量波动玄学!从法拉第电磁定律到底层 C/C++ 流量累积算法,深度解密工业级电磁流量计选型与开发
c语言·c++·算法
中达瑞和-高光谱·多光谱7 小时前
1nm到8nm光谱分辨率,你的应用该选哪款光谱相机?
算法·高光谱·高光谱相机
脱胎换骨-军哥7 小时前
C++/Rust无缝互操作:混合系统新常态
开发语言·c++·rust