费解的开关问题

题目如下:

你玩过"拉灯"游戏吗?

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 中

相关推荐
可均可可27 分钟前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite
幸运超级加倍~42 分钟前
软件设计师-上午题-16 算法(4-5分)
笔记·算法
白子寰1 小时前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
yannan201903131 小时前
【算法】(Python)动态规划
python·算法·动态规划
埃菲尔铁塔_CV算法1 小时前
人工智能图像算法:开启视觉新时代的钥匙
人工智能·算法
EasyCVR1 小时前
EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何解决?
人工智能·算法·ffmpeg·音视频·webrtc·监控视频接入
linsa_pursuer1 小时前
快乐数算法
算法·leetcode·职场和发展
小芒果_011 小时前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
qq_434085901 小时前
Day 52 || 739. 每日温度 、 496.下一个更大元素 I 、503.下一个更大元素II
算法
Beau_Will1 小时前
ZISUOJ 2024算法基础公选课练习一(2)
算法