费解的开关问题

题目如下:

你玩过"拉灯"游戏吗?

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 中

相关推荐
暮色_年华10 分钟前
Modern Effective C++ Item 11:优先考虑使用deleted函数而非使用未定义的私有声明
c++
流星白龙12 分钟前
【C++习题】10.反转字符串中的单词 lll
开发语言·c++
Smile丶凉轩35 分钟前
微服务即时通讯系统的实现(服务端)----(1)
c++·git·微服务·github
肥猪猪爸44 分钟前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos44 分钟前
环形缓冲区
数据结构
readmancynn1 小时前
二分基本实现
数据结构·算法
萝卜兽编程1 小时前
优先级队列
c++·算法
Bucai_不才1 小时前
【数据结构】树——链式存储二叉树的基础
数据结构·二叉树
盼海1 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步1 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表