AcWing95.费解的开关

news/2024/5/18 21:29:27 标签: 位运算, 枚举, 递推

题目

你玩过“拉灯”游戏吗?25 盏灯排成一个 5×5 的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。

我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯。下面这种状态

10111
01101
10111
10000
11011

在改变了最左上角的灯的状态后将变成:

01111
11101
10111
10000
11011

再改变它正中间的灯后状态将变成:

01111
11001
11001
10100
11011

给定一些游戏的初始状态,编写程序判断游戏者是否可能在 6 步以内使所有的灯都变亮。

输入格式

第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。

以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。

每组数据描述了一个游戏的初始状态。

各组数据间用一个空行分隔。

输出格式

一共输出 n 行数据,每行有一个小于等于 6 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。

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

数据范围

0 < n ≤ 500 0<n≤500 0<n500

输入样例

3
00111
01011
10001
11010
11100

11101
11101
11110
11111
11111

01111
11111
11111
11111
11111

输出样例

3
2
-1

思路

很容易发现三个性质:

  1. 每个位置至多只会被点击一次。
  2. 若固定了第 0 行(不能再改变第 0 行),则满足题意的点击方案至多只有1种。原因是:当第 i i i 行某一位为 0 时,若前 i i i 行已被固定,只能点击第 i + 1 i+1 i+1 行该位置上的数字才能使第 i i i 行的这一位变成1。从上到下按行使用归纳法可得上述结论。
  3. 点击的先后顺序不影响最终结果。

于是,不妨先考虑第 0 行如何点击【因为如果不改变当前第 0 行的状态,得到的结果可能并不是最优解】。枚举第 0 行的点击方法( 2 5 = 32 2^5 = 32 25=32 种)后,就可以认为第 0 行 “固定不变”,再考虑第 1 ~ 4 行如何点击。 而按照上述性质2,此时的第 1 ~ 4 行的点击方案是确定的——从第 0 行开始递推,当第 i i i 行某一位为 0 时,点击第 i + 1 i+1 i+1 行该位置上的数字。若到达第 n − 1 n - 1 n1 行时不全为 1 【第 n − 1 n - 1 n1 行已经为最后一行,状态不能再修改了】,说明这种点击方式不合法。在所有合法的点击方式中取点击次数最少的就是答案。对第 0 行的 32 次枚举涵盖了该问题的整个状态空间,因此该做法是正确的。

对于第一行点击方法的枚举,可以采用位运算的方式,枚举0 ~ 31 这 32 个 5 位二进制数,若二进制数的第 k ( 0 ≤ k < 5 ) k(0 \le k \lt 5) k0k<5 位为1,就点击该矩阵第 0 行第 k k k 列的数字。

代码

#include<bits/stdc++.h>
using namespace std;

const int INF = 1000000;
const int N = 5;
char matrix[N][N];

//某个位置的灯状态被修改,则一共有5个位置的灯状态发生改变(上下左右中)
int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};

//修改(x,y)位置的灯的状态
void turn(int x, int y) {
    //(x,y) 位置上的状态发生改变,则要同步修改(a,b)位置上的状态
    for (int i = 0; i < 5; i++) {
        int a = x + dx[i];
        int b = y + dy[i];
        if (a >= 0 && a < 5 && b >= 0 && b < 5) { //判断位置是否合法
            matrix[a][b] ^= 1; //修改(a,b)位置的状态,如果原先是0就变为1,原先是1就变为0
        }
    }
}

int work() {
    int ans = INF;
    
    //枚举第0行的状态(所有状态的编码为k)
    //第j位为1表示在第j位进行了一次操作 
    for (int k = 0; k < (1 << 5); k++) {
        int step = 0;
        char backup[N][N];
        memcpy(backup, matrix, sizeof(matrix)); //matrix复制一份放到backup中
        for (int j = 0; j < 5; j++) {
            if ((k >> j) & 1) {//如果是1,表示要第j位要按一下
                step++;
                turn(0, j);
            }
        }
        
        //第0行的状态已经固定
        //开始递推前四行的状态
        //用第i行的状态确定第i+1行的状态
        for (int i = 0; i < 4; i++) { //推到倒数第二行
            for (int j = 0; j < 5; j++) {
                if (matrix[i][j] == '0') { //将同列的下一个位置修改
                    step++;
                    turn(i + 1, j);
                }
            }
        }
        
        //判断最后一行是否全部为1
        bool successful = true;
        for (int j = 0; j < 5; j++) {
            if (matrix[4][j] == '0') {
                successful = false;
                break;
            }
        }
        
        if (successful) ans = min(ans, step);
        
        memcpy(matrix, backup, sizeof(backup)); //矩阵恢复原状
    }
    
    if (ans > 6) ans = -1;
        
    return ans;
}

int main() {
    int n;
    cin >> n;
    while (n--) {
        for (int i = 0; i < 5; i++)
            cin >> matrix[i];
        
        cout << work() << endl;
        
    }
    return 0;
}

http://www.niftyadmin.cn/n/5145140.html

相关文章

【蓝桥杯基础题】星期一

👑专栏内容:蓝桥杯刷题⛪个人主页:子夜的星的主页💕座右铭:前路未远,步履不停目录 一、题目描述二、题目分析三、代码汇总1、C++代码2、Java代码四、总结求解闰年一、题目描述 题目链接:星期一 整个20世纪(1901年1月1日至2000年12月31日之间),一共有多少个星期一…

点焊机的数据校验

下班了&#xff0c;今天又来看看小编学习了什么内容先吧&#xff01;&#xff01;&#xff01;今天原本以为是摸鱼的一天&#xff0c;突然间传来了机器出现问题的消息&#xff01;机器比较老旧&#xff0c;怀疑填数据出现问题&#xff0c;就下达了机器原来数据进行校验的活&…

生产环境评估机器

学习了kafka的原理知识后&#xff0c;还要学会如何评估生产环境集群&#xff0c;如果是一个大数据架构师&#xff0c;这个是必须要会的&#xff0c;比如kafka集群、Hbase集群、hadoop集群&#xff0c;评估集群的方式差不多&#xff0c;现在以kafka为例。 电商平台&#xff0c;需…

llava1.5模型安装、预测、训练详细教程

引言 本博客介绍LLava1.5多模态大模型的安装教程、训练教程、预测教程&#xff0c;也会涉及到hugging face使用与wandb使用。 源码链接:点击这里 demo链接:点击这里 论文链接:点击这里 一、系统环境 ubuntu 20.04 gpu: 2*3090 cuda:11.6 二、LLava环境安装 1、代码下载…

0基础学习PyFlink——使用datagen生成流式数据

大纲 可控参数字段级规则生成方式数值控制时间戳控制 表级规则生成速度生成总量 结构生成环境定义行结构定义表信息 案例随机Int型顺序Int型随机型Int数组带时间戳的多列数据 完整代码参考资料 在研究Flink的水印&#xff08;WaterMark&#xff09;技术之前&#xff0c;我们可能…

【云栖大会】我与“云栖”共成长

目录 一&#xff1a;何为云栖 二&#xff1a;初识云栖 三&#xff1a;被云栖圈粉 四&#xff1a;感受与体会 五&#xff1a;期待与建议 一&#xff1a;何为云栖 我们都说“万物皆可云”&#xff0c;这充分说明了云计算的重要性&#xff0c;而阿里云是云计算行业的领头羊之一…

linux下df -h 命令一直卡住的解决方法

在Linux中&#xff0c;偶尔遇到用 df -h 查看磁盘情况时&#xff0c;一直卡住无法显示结果。 解决方法&#xff1a; 1、首先使用strace追踪到底执行到哪里卡住 $ strace df -h 2、如果没有strace命令则进行安装 $ yum install strace -y 3、显示出卡住的地方&#xff0c;如…

MySQL数据库入门到大牛_01_内容简介

在企业中高级程序员以上级别常常要求是精通MySQL。任何一项技术一旦深入&#xff0c;体系都是繁杂的&#xff0c;想要真正掌握&#xff0c;需要掌握底层的逻辑&#xff0c;梳理清知识脉络&#xff0c;能够以架构师的思路学习MySQL&#xff0c;才能以不变应万变。此篇开始介绍My…