《算法竞赛·快冲300题》每日一题:“点灯游戏”
《算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。
文章目录
- 题目描述
- 题解
- C++代码
- Java代码
- Python代码
“ 点灯游戏” ,链接: http://oj.ecustacm.cn/problem.php?id=1134
题目描述
【题目描述】 有一个n*n的灯泡矩阵,b表示灯暗,w表示灯亮。每个灯的位置上都有控制着这盏灯的按钮。当按下一个按钮后,该按钮以及周围位置(上下左右)的灯都会改变状态(亮->暗,暗->亮)。最少按下多少个按钮可以使得所有的灯都亮或者都暗。
【输入格式】 输入有多组数据,每组数据第一行有一个整数n(1≤n≤10),接下来n行,每行n个字符表示初始的灯泡矩阵。
【输出格式】 如果可以使得所有的灯泡都亮或者都暗,输出最少按下的按钮数目。如果无法达到,输出"Impossible"(不含引号) 。
【输入样例】
4
bwwb
bbwb
bwwb
bwww
4
bwbw
wwww
bbwb
bwwb
【输出样例】
4
Impossible
题解
“点灯游戏”是一个经典问题,有多种解法。
如果没有限制“最少按钮数”,只要求能实现全暗或全灭,如何操作?这里介绍一种被称为“首行穷举法”的方法,简单易行。设目标是把所有的灯变黑(暗),操作如下:
(1)第一行不按动按钮,只需找到白灯的位置;
(2)第二行对应第一行的白灯的位置,都是按钮,按下后,它上下左右的灯都变色,特别是上一行的白灯都会变黑,从而保证第一行都变成黑色;
(3)每一行的按钮,都对应上一行的白灯,使上一行全变黑。
本题要求得“最少按钮数”,可以把所有按钮都试一遍,找到最少的那种。为了减少尝试的次数,可以结合上述方法。本题的n≤10,规模很小,这种暴力法也可行。
假设目标是最后都变成黑色,从第一行开始,逐行按动按钮。
第一行有0000~1111共16种按按钮的方法。0000表示1个都不按,0001表示只按第1个按钮,0010表示只按第2个按钮,0011表示按第1、第2个按钮,…,等等。
第一行选择一种方法按完之后,继续按动第二行。第二行如何按?显然要保证第一行都变成黑色才行。那么应该让第二行的按钮位置跟第一行的白色位置一样,因为第二行的按钮按动之后,它上面的白色会跟着变成黑色。
按上述规则继续按后面的行,直到结束。
下面举例说明。图中的“初态”是第一个样例的灯,黑表示暗,白表示亮。左上角坐标(0,0),右下角坐标(3,3)。
(1)第一行的按钮设置。以第一行按0011为例,就是按第1、2个按钮。按第1个按钮(0,0)后得到图(1),再按第2个按钮(0,1)后得到图(2)。记录两个按钮的坐标(0,0)、(0,1)。
(2)第二行的按钮设置。此时第一行只有第2个灯是白的,需要变成黑色。那么第二行必须按第2个按钮,才能让上面的白灯变成黑灯。第二行需要按的按钮的坐标是(1,1),得到图(3)的结果,第一行全黑了。
(3)第三行的按钮设置。由于第二行全是黑的,所以第三行不用按了。
(4)第四行的按钮设置。第三行的第3个灯是白的,需要变成黑色。那么第四行必须按第3个按钮,才能让上面的白灯变成黑灯。得到图(4)的结果,第三行全黑了。第四行需要按的按钮坐标是(3,2)。
这四行结束后,第四行也变成了全黑,说明这是一次成功的操作,共按了4个按钮。
第一行共有16种按钮设置方法,都按以上步骤操作一遍,其中按动按钮最少的就是结果全是黑灯的答案。
以上假设最后都是黑色,也可以假设最后都是白色,再操作一次即可。取最少的按钮次数就是本题的答案。
请读者按这个思路编码。下面的代码供参考。
【重点】 思维 。
C++代码
#include<bits/stdc++.h>
using namespace std;
char Map[11][11];
int n;
int GetBit(int x, int i){ //取出x的第i位return (x >> i) & 1;
}
void SetBit(int &x, int i, int v){ //将x的第i位设置成vif(v) x |= (1 << i);else x &= ~(1 << i);
}
void FlipBit(int &x, int i){ //将x的第i位取反x ^= (1 << i);
}
int solve(){int oriLights[11]; //灯的初态int Lights[11]; //按动按钮之后的灯的新状态int result[11]; //存需要按动的按钮int ans = n * n + 1; //需要按动的按钮数不会大于n*nmemset(oriLights, 0, sizeof(oriLights));for(int i = 0; i < n; i++) //把灯用二进制的位来表示,第i行,第j列for(int j = 0; j < n; j++){if(Map[i][j] == 'b') SetBit(oriLights[i], j, 0); //0表示暗else SetBit(oriLights[i], j, 1); //1表示亮}for(int k = 0; k < (1<<n); k++) { //k是第0行的按钮,有0000~1111种按钮设置memcpy(Lights, oriLights, sizeof(oriLights)); int switchs = k; //第0行的按钮,例如k=0011,就是按第1、2个按钮for(int i = 0; i < n; i++) { //逐一处理每行的灯result[i] = switchs; //用result[i]记录第i行的按钮for(int j = 0; j < n; j++) { //逐一处理每一列的灯if(GetBit(switchs, j)) { if(j > 0) FlipBit(Lights[i], j-1); //j前面的第j-1灯变色FlipBit(Lights[i], j); //第j个灯变色if(j < n-1) FlipBit(Lights[i], j+1); //j后面的第j+1灯变色}}if(i < n-1) Lights[i+1] ^= switchs; //修改下一行的灯switchs = Lights[i]; //第i+1行按钮位置和第i行灯的位置相同}if(Lights[n-1] == 0) { //最后一行也全变黑了,成功int tmp = 0; //tmp为开关矩阵中1的数目for(int i = 0; i < n; i++) //(i,j)就是需要按动的按钮坐标for(int j = 0; j < n; j++)if(result[i] & (1<<j))tmp++;ans = min(ans, tmp);}}return ans;
}
int main(){while(scanf("%d", &n) != EOF) {memset(Map, 0, sizeof(Map));for(int i = 0; i < n; i++) scanf("%s", Map[i]);int ans = solve(); //以全黑为目标做一次for(int i = 0; i < n; i++) //反过来以全白为目标做一次for(int j = 0; j < n; j++)if(Map[i][j] == 'b') Map[i][j] = 'w';else Map[i][j] = 'b';ans = min(ans, solve());if(ans > n * n) puts("Impossible");else printf("%d\n", ans);}return 0;
}
Java代码
import java.util.*;
public class Main { static int GetBit(int x, int i) {return (x >> i) & 1;} static int SetBit(int x, int i, int v) {if (v == 1) x |= (1 << i);else x &= ~(1 << i);return x;} static int FlipBit(int x, int i) {x ^= (1 << i);return x;} static int solve(int n, String[] Map) {int[] oriLights = new int[n];for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {if (Map[i].charAt(j) == 'b') oriLights[i] &= ~(1 << j);else oriLights[i] |= (1 << j);}int ans = n * n + 1;for (int k = 0; k < (1 << n); k++) {int switchs = k;int[] Lights = oriLights.clone();int[] result = new int[n];for (int i = 0; i < n; i++) {result[i] = switchs;for (int j = 0; j < n; j++) {if (GetBit(switchs, j) == 1) {if (j > 0) Lights[i] = FlipBit(Lights[i], j-1);Lights[i] = FlipBit(Lights[i], j);if (j < n-1) Lights[i] = FlipBit(Lights[i], j+1);}}if (i < n-1) Lights[i+1] ^= switchs;switchs = Lights[i];}if (Lights[n-1] == 0) {int tmp = 0;for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if ((result[i] & (1 << j)) != 0) tmp++;ans = Math.min(ans, tmp);}}if (ans > n * n) return -1;else return ans;}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);while (scanner.hasNext()) {int n = scanner.nextInt();if (n == 0) break; String[] Map = new String[n];for (int i = 0; i < n; i++) Map[i] = scanner.next();int ans = solve(n, Map);// 循环遍历数组并替换字符for (int i = 0; i < n; i++) {Map[i] = Map[i].replace('b', 'x'); // 将'b'替换为临时字符'x'Map[i] = Map[i].replace('w', 'b'); // 将'w'替换为'b'Map[i] = Map[i].replace('x', 'w'); // 将临时字符'x'替换为'w'}ans = Math.min(ans, solve(n, Map));if (ans == -1) System.out.println("Impossible");else System.out.println(ans);}scanner.close();}
}
Python代码
import sys
def GetBit(x, i): return (x >> i) & 1def SetBit(x, i, v):if v: x |= (1 << i)else: x &= ~(1 << i)return xdef FlipBit(x, i):x ^= (1 << i)return xdef solve(n, Map):oriLights = [0] * nfor i in range(n):for j in range(n):if Map[i][j] == 'b': oriLights[i]=SetBit(oriLights[i], j, 0) else: oriLights[i]=SetBit(oriLights[i], j, 1) ans = n * n + 1for k in range(1 << n):switchs = kLights = oriLights[:]result = [0] * nfor i in range(n):result[i] = switchsfor j in range(n):if GetBit(switchs, j):if j > 0: Lights[i] = FlipBit(Lights[i], j-1)Lights[i] = FlipBit(Lights[i], j)if j < n-1: Lights[i] = FlipBit(Lights[i], j+1)if i < n-1: Lights[i+1] ^= switchsswitchs = Lights[i]if Lights[-1] == 0:tmp = 0for i in range(n):for j in range(n):if result[i] & (1 << j):tmp += 1ans = min(ans, tmp)return ansfor line in sys.stdin:n = int(line.strip())if n == 0: breakMap = []for i in range(n): Map.append(input().strip())ans = solve(n, Map)F = {}F['b'] = 'w'F['w'] = 'b'for i in range(n):Map[i] = ''.join([F[x] for x in Map[i]])ans = min(ans,solve(n, Map))if ans > n * n: print("Impossible")else: print(ans)
相关文章:
《算法竞赛·快冲300题》每日一题:“点灯游戏”
《算法竞赛快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 点…...
常见高级语言的输入与输出训练(一)
文章目录 题目概述1 输入描述: 输出描述: 输入 输出 示例C语言代码 题目概述2 题目描述 输入描述: 输出描述: 输入 输出 示例Java代码 前言 本文主要讲解两个算法题的代码实现 题目概述1 计算ab 打开以下链接可以查看正确的代码 数据范围:数据组数满…...
恭喜!龙蜥获得 2023 大学生操作系统设计赛二等奖及特殊贡献奖
经过多月的激烈角逐,2023 全国大学生系统能力大赛操作系统设计赛(以下简称“2023 大学生操作系统赛”) 圆满结束。经过 2023 大学生操作系统赛评审组和技术委员会的复核,面向全国公布了此次大赛的获奖名单。龙蜥社区不负众望&…...
中项系统集成项目管理2023上半年真题及解析
中项系统集成项目管理2023上半年真题及解析 上午题1. 在 (1) 领域,我国还远未达到世界先进水平,需要发挥新型举国体制优势,集中政府和市场两方面的力量全力发展2. ChatGPT于 2022年 11 月 30 日发布,它是人工智能驱动的 (2) 工具3…...
实时显示当前文件夹下的文件大小,shell脚本实现
图片来源于网络,如果侵权请联系博主删除! 需求: 写一个shell终端命令,实时显示当前文件夹下的文件大小 实现: 您可以使用以下的Shell脚本命令来实时显示当前文件夹下的文件大小: while true; docleardu …...
7、Spring之依赖注入源码解析(下)
resolveDependency()实现 该方法表示,传入一个依赖描述(DependencyDescriptor),该方法会根据该依赖描述从BeanFactory中找出对应的唯一的一个Bean对象。 @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,@Null…...
图片码二次渲染绕过
目录 一、环境 1、代码 2、文件处理方式 3、图片码的制作 二、绕过图片重构 1、可行性分析 2、数据比对 3、完成绕过 一、环境 以upload-labs靶场第十七关为例 1、代码 源码为: <?php include ../config.php; include ../head.php; include ../menu.…...
点评项目核心内容
目录 拦截器设置 集群的session共享问题 基于redis实现共享session登录 创建bean对象技巧 什么是缓存 使用缓存来处理对象 使用String类型缓存来处理集合 缓存更新策略 主动更新策略 缓存穿透 空串""和null的区别 缓存null值解决穿透问题 缓存雪崩 缓存击穿…...
海外商城小程序为什么这么受欢迎?
随着全球化的进程海外商城小程序在近年来获得了广泛的关注和使用。海外商城小程序是一种基于互联网技术的应用程序,为用户提供了便捷的购物体验和跨境交易服务。本文将深入探讨海外商城小程序的受欢迎原因,从多个维度进行分析就其未来发展进行思考&#…...
Linux Day13 ---信号量
一、信号量 1.1 一些概念 用来管理对资源的访问 一个特殊的变量,只允许对它进行等待(wait)和发送信号(signal),代表可用资源个数, 取0,1 二值信号量 取 3,5 计数信号量 p操作:原子减一,代表获取资源,可能阻塞 v…...
《动手学深度学习 Pytorch版》 4.10 实战Kaggle比赛:预测比赛
4.10.1 下载和缓存数据集 import hashlib import os import tarfile import zipfile import requests#save DATA_HUB dict() DATA_URL http://d2l-data.s3-accelerate.amazonaws.com/def download(name, cache_diros.path.join(.., data)): #save"""下载一个…...
jQuery补充
文章目录 简介安装语法选择器元素选择器#id 选择器.class 选择器事件常用事件方法 效果显示隐藏淡入淡出滑动动画停止动画获取内容和属性添加元素删除元素操作css父辈 💛💛孔子云:温故而知新,可以为师矣💛💛…...
goaccess 日志分析 nginx
分析命令: goaccess -a -d -f /mnt/winshare/access-2023070112.log -p goaccess.conf -o /mydata/nginx/html/2023070112_new.html分析日志时的参数 goaccess使用参数详解-a 开启 UserAgent 列表。开启后会降低解析速度 -c 在程序开始运行时显示 日志/日期 配…...
认养一头牛———众筹+合伙人商业模式解析
2016年成立以来,认养一头牛致力于打造数字化乳业第一品牌,只为一杯好牛奶。公司在创立三年内完成了10个亿销售目标,被业界称为新消费品牌黑马,一举闯入互联网新消费梯队的视线。未来三年,认养一头牛将着力打造全国最大…...
前端面试的话术集锦第 11 篇:高频考点(React和Vue两大框架)
这是记录前端面试的话术集锦第十一篇博文——高频考点(React和Vue两大框架),我会不断更新该博文。❗❗❗ React 和Vue应该是国内当下最火热的前端框架。当然,Angular也是一个不错的框架,但是这个产品,国内使用的人很少,因而,框架的章节中不会涉及到Angular的内容。 这…...
前端js下载zip文件异常问题解决
目录 一,本文解决问题如下 二,原下载代码 1,ajax get 下载文件 2,下载异常图: 三,成功下载的 1, JQuery 实现文件下载xhr 2,图例 引言: 本人使用的ajax 下载&…...
深度学习面试八股文(2023.9.06)
一、优化器 1、SGD是什么? 批梯度下降(Batch gradient descent):遍历全部数据集算一次损失函数,计算量开销大,计算速度慢,不支持在线学习。随机梯度下降(Stochastic gradient desc…...
Linux入门-网络基础|网络协议|OSI七层模型|TCP/IP五层模型|网络传输基本流程
文章目录 一、网络基础 二、网络协议 1.OSI七层模型 2.TCP/IP五层(或四层)模型 三、网络传输基本流程 1.网络传输流程图 2.数据包封装和分用 四、网络中的地址管理 1.IP地址 2.MAC地址 一、网络基础 网络发展最初是独立模式,即计算…...
docker系列(2) - 常用命令篇
文章目录 2. docker常用命令2.1 参数说明(tomcat案例)2.2 基本命令2.3 高级命令2.4 其他 2. docker常用命令 2.1 参数说明(tomcat案例) 注意如果分成多行,\后面不能有空格 # 拉取运行 docker run \ -d \ -p 8080:8080 \ --privilegedtrue \ --restartalways \ -m…...
Debian11安装MySQL8.0,链接Navicat
图文小白教程 1 下载安装MySQL1.1 从MySQL官网下载安装文件1.2 安装MySQL1.3 登录MySQL 2 配置Navicat远程访问2.1 修改配置2.2 Navicat 连接 end: 卸载 MySQL 记录于2023年9月,Debian11 、 MySQL 8.0.34 1 下载安装MySQL 1.1 从MySQL官网下载安装文件 打开 MySQ…...
vue项目中使用特殊字体的步骤
写在前面 在项目中使用特殊字体,需要注意,所使用的特殊字体是否被允许商用或是个人开发,以及如何使用,切记不要侵权。 首先需要在对应字体网站下载字体文件,取出里面后缀名为.ttf的文件 然后把该文件放到src -> ass…...
激光雷达检测负障碍物(附大概 C++ 代码)
检测效果如图,红色是正负的障碍物点: 障碍物根据其相对于地面的高度可以分为两类:正向障碍物和负向障碍物。在室外环境中,负障碍物是沟渠、悬崖、洞口或具有陡峭负坡度的地形,可能会造成安全隐患。 不慎通过道路坑洼处…...
【每日一题】9.13 PING是怎么工作的?
PING命令的作用是什么? PING命令是计算机网络中常用的命令之一,它的作用是测试两台计算机之间的连通性以及测量数据包往返的时间。 PING命令的工作原理是什么? PING命令的工作原理涉及到ICMP(Internet Control Message Protocol)和网络协议栈的操作: 1.发送ICMP …...
【Python百日进阶-Web开发-Peewee】Day279 - SQLite 扩展(四)
文章目录 12.2.10 class FTSModel 12.2.10 class FTSModel class FTSModel与FTS3 和 FTS4 全文搜索扩展VirtualModel一起使用的子类。 FTSModel 子类应该正常定义,但是有几个注意事项: 不支持唯一约束、非空约束、检查约束和外键。字段索引和多列索引…...
Postman接口压力测试 ---- Tests使用(断言)
所谓断言,主要用于测试返回的数据结果进行匹配判断,匹配成功返回PASS,失败返回FAIL。 下图方法一,直接点击右侧例子函数,会自动生成出现在左侧窗口脚本,只需修改数据即可。 方法二:直接自己写脚…...
nvue文件中@click.stop失效
在nvue文件中在子元素使用click.stop失效,父元素的事件触发了 在uniapp开发中nvue文件是跟vue文件是不一样的,就比如click.stop阻止点击事件继续传播就失效了,这时我们需要在子元素事件中添加条件编译,这样就会解决这个问题 // …...
【微信小程序开发】宠物预约医疗项目实战-开发功能介绍
【微信小程序开发】宠物医院项目实战-开发功能介绍 前言 本项目主要带领大家学习微信小程序开发技术,通过一个完整的项目系统的学习微信小程序的开发过程。鉴于一些同学对视频教学跟不上节奏,为此通过图文描述的方式,完整的将系统开发过程记…...
vue网页缓存页面与不缓存页面处理
在主路由页面 <template><div style"height: 100%"><!-- 缓存 --><keep-alive><router-view v-if"$route.meta.keepAlive"></router-view></keep-alive><!-- 不缓存 --><router-view v-if"!$rou…...
AI系统论文阅读:SmartMoE
提出稀疏架构是为了打破具有密集架构的DNN模型中模型大小和计算成本之间的连贯关系的——最著名的MoE。 MoE模型将传统训练模型中的layer换成了多个expert sub-networks,对每个输入,都有一层special gating network 来将其分配到最适合它的expert中&…...
AD20多层板设计中的平电层设计规则
一般情况下的多层板设计非常复杂,尤其层叠的次序以及平电层的电源层设计,Gnd层的设计比较简单,不需要过多的关注,但是电源层的设计非常关键,常常让人感到无法下手的感觉,这里介绍一个简单的防盲很快的让你上…...
广州易网网站建设/站长统计ios
(注:环境Mac OS X Lion 10.7.3 Xcode 4.2.1 iOS SDK 5.0.)一、新建iOS Application工程,选择Single View Application,不要选中Use Storyboard.假设指定的是product name和class prefix都是one,则完成后自动生成代码视图如下图:…...
长沙网站建设哪家靠谱/郑州见效果付费优化公司
String.prototype.charAt()str.charAt(index)返回字符串中指定位置的字符。字符串中的字符从左向右索引,第一个字符的索引值为 0,最后一个字符(假设该字符位于字符串 stringName 中)的索引值为 stringName.length - 1。如果指定的 index 值超出了该范围&…...
现在的官方网站怎么做的/百度网站优化软件
笔记内容整理自mooc上北京理工大学嵩天老师python系列课程数据分析与展示,本人小白一枚,如有不对,多加指正 1.python自带的图像库PIL 1.1常用API Image.open() Image.fromarray() im.save() convert(L) b.astype(uint8)(这个API用于处理后的数…...
网站关键词基础排名怎么做/东莞网络营销优化
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址&a…...
上海网站建设哪家/管理微信软件
**众所周知IE浏览器不兼容<input type"date">的html5时间插件,**下面介绍一种支持IE浏览器的jquery时间插件, 1.先引入jquery:<link rel"stylesheet" href"common/css/dcalendar.picker.css"/> &l…...
做类似猪八戒网的网站/郑州品牌网站建设
文章目录1.sudo !!2.mtr 命令3.nl 命令4.shulf 和tree 、pstreeshulf 命令tree命令pstree 这个是进程按树形结构显示,显示当前进程以及相关子进程,输出信息跟“tree”类似5.last 命令6.curl ifconfig.me7.lsof -i:端口号8.cut 命令9.seq 命令11.关于 脚本…...