(题面来自ACwing)

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

我们用数字“1”表示一盏开着的灯,用数字“0”表示关着的灯。

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

输入格式

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

以下若干行数据分为n组,每组数据有5行,每行5个字符。每组数据描述了一个游戏的初始状态。各组数据间用一个空行分隔。

输出格式

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

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

  题意的本质是:求解把一个5 * 5的01方阵通过上述操作变换成为仅由1构成的方阵的最小步数。如果单纯每次枚举改变的点来爆搜,状态空间的大小不能承受,显然行不通。

  实际上,题中所给的变换具有两个很重要的性质。首先,每个点最多被变换一次,因为重复的操作是无效的;第二,相同操作的不同顺序不会影响最终结果,因为累计在每个位置上的效果都一样。

  从这两点出发,我们发现可以枚举部分变换来递推所有的操作。具体来说,考虑逐行进行变换,那么当前行i上面所有行所进行的变换已经确定了;如果第i-1行上的第k个位置上有0,那么只能通过改变第i行的第k个位置使第i-1行合法,这是解答本题的关键。因此,我们可以二进制枚举在第一行进行的2^5 = 32种变换,然后依次递推第2~5行的操作。最后检查第五行是否全部为1,若第五行状态合法就用当前的步数更新答案即可。

  从这个题吸取的教训是,要慎用语句"ios::sync_with_stdio(0)",因为这个指令取消了cin和C标准输入输出的兼容性,一旦手滑同时使用cin和getchar、scanf等C库读入函数就会发生错误。这句话最好在读入字符串时再考虑适用,平时应该手写快读来避免悲剧。

代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <ctime>
  6. using namespace std;
  7. const int inf = 0x3f3f3f3f;
  8. int sw[10][10], tmp[10][10], cnt, ans;
  9. int addx[5] = {0, 0, 0, -1, 1}, addy[5] = {0, 1, -1, 0, 0};
  10. void change(int x, int y, int a[10][10]) {
  11. int tx, ty;
  12. for (int i = 0; i < 5; ++i) {
  13. tx = x + addx[i], ty = y + addy[i];
  14. if (a[tx][ty] == -1) continue;
  15. a[tx][ty] = !a[tx][ty];
  16. }
  17. ++cnt;
  18. }
  19. void init(int x) {
  20. memcpy(tmp, sw, sizeof(tmp));
  21. for (int i = 1; i <= 5; ++i)
  22. if (x >> (i - 1) & 1)
  23. change(1, i, tmp);
  24. }
  25. int main() {
  26. int T;
  27. cin >> T;
  28. while (T--) {
  29. ans = inf;
  30. memset(sw, -1, sizeof(sw));
  31. char ch;
  32. for (int i = 1; i <= 5; ++i) {
  33. while (!isdigit(ch))
  34. ch = getchar();
  35. for (int j = 1; j <= 5; ++j)
  36. sw[i][j] = ch - 48, ch = getchar();
  37. }
  38. /*      for (int i = 1; i <= 5; ++i) {
  39. for (int j = 1; j <= 5; ++j)
  40. cout << sw[i][j] << " ";
  41. cout << endl;
  42. }*/
  43. for (int x = 0; x < 32; ++x) {
  44. cnt = 0;
  45. init(x);
  46. for (int i = 2; i <= 5; ++i)
  47. for (int j = 1; j <= 5; ++j)
  48. if (!tmp[i - 1][j])
  49. change(i, j, tmp);
  50. for (int i = 1; i <= 5; ++i)
  51. if (!tmp[5][i]) cnt = inf;
  52. ans = min(ans, cnt);
  53. }
  54. if (ans <= 6)
  55. cout << ans << endl;
  56. else puts("-1");
  57. }
  58. return 0;
  59. }

【ACwing 95】费解的开关——枚举 + 搜索的更多相关文章

  1. AcWing 95 费解的开关

    目录 前言 题目链接 思路 代码 前言 博客咕咕咕了好久了,是时候写一下了 题目链接 AcWing 95 费解的开关 思路 首先可以看出 1.每一个位置顶多只会操作一次.因为如果操作两次的话,相当于不 ...

  2. ACWING 95 费解的开关 解题记录

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

  3. CH0201 费解的开关 枚举

    正解:枚举 解题报告: 入门傻逼题,思维难度不高代码量极小,非常适合上手 然后傻逼的我第二次看这道题的时候依然没想到解法:D 没有办法,就想着写个笔记好歹记录一下以后多复习几次就记着了趴qwq 就是, ...

  4. AcWing95. 费解的开关 枚举+位运算

    这道题的确比较难想,首先我们知道图比较小,有可能是枚举,那么该如何枚举呢??? 你可以发现,我们只要把第一排定了,并且保证第一排不准动,那么答案就定了 也就是说,我们首先用二进制枚举,枚举第一行需要翻 ...

  5. ACAG 0x02-4 费解的开关

    ACAG 0x02-4 费解的开关 对于这道题,我们不难发现如下性质: 每个位置之多被点击一次: 点击的先后顺序不影响结果: 若确定了第$1$行,则接下来可能的点击方案就只有$1$种.具体原因是:当第 ...

  6. TyvjP1266 费解的开关

    P1266 费解的开关 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述     你玩过“拉灯”游戏吗?25盏灯排成一个5x5的方形.每一个灯都有一个开关,游戏 ...

  7. hdu4431 Mahjong 枚举搜索。。

    japanese麻将什么玩意..都没有豪华七对... 没什么难的 就是枚举搜索了 分三种类型的胡牌 f1是七对 f2是十三幺 f3是普通的胡牌 就先找一对 再找三个三个的 就是一直超时..在峰峰的指导 ...

  8. AcWing 92. 递归实现指数型枚举

    题目链接:https://www.acwing.com/problem/content/description/94/ 题意:从 n 个数中选取数字,输出所有的选取可能 idea:枚举所有取数可能,就 ...

  9. HDU 4900 NO ACM NO LIFE(概率+枚举+搜索)(2014 Multi-University Training Contest 4)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4900 Problem Description There is an old country and ...

随机推荐

  1. Java学习的第七天

    1.今天学了数组 数组名称.length是数组的长度. 数组打印 二维数组: 多维数组同二维数组类似. 最大值最小值算法. 2.在输入过程中的 定义 int 名=con.nextInt();当时不懂. ...

  2. Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号

    Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号 背景 上一讲我们介绍了Unix IPC中的2种管道. 回顾一下上一讲的介绍,IPC的方式通常有: Unix IPC包括:管道 ...

  3. [Luogu P2341] [HAOI2006]受欢迎的牛 (缩点+bitset)

    题面 传送门:https://www.luogu.org/problemnew/show/P2341 Solution 前排提示,本蒟蒻做法既奇葩又麻烦 我们先可以把题目转换一下. 可以把一头牛喜欢另 ...

  4. 适合 C++ 新手学习的开源项目——在 GitHub 学编程

    作者:HelloGitHub-小鱼干 俗话说:万事开头难,学习编程也是一样.在 HelloGitHub 的群里,经常遇到有小伙伴询问编程语言如何入门方面的问题,如: 我要学习某一门编程语言,有什么开源 ...

  5. Java进阶专题(十六) 数据结构与算法的应用(上)

    前言 ​ 学习算法,我们不需要死记硬背那些冗长复杂的背景知识.底层原理.指令语法--需要做的是领悟算法思想.理解算法对内存空间和性能的影响,以及开动脑筋去寻求解决问题的最佳方案.相比编程领域的其他技术 ...

  6. 写时复制集合 —— CopyOnWriteArrayList

    前言 JUC 下面还有一个系列的类,都是 CopyOnWriteXXX ,意思是写时复制,这个究竟是怎么回事?那就以 CopyOnWriteArrayList 为切入点,一起了解写时复制是怎么回事? ...

  7. EntityFramework Core上下文实例池原理分析

    前言 无论是在我个人博客还是著作中,对于上下文实例池都只是通过大量文字描述来讲解其基本原理,而且也是浅尝辄止,导致我们对其认识仍是一知半解,本文我们摆源码,从源头开始分析.希望通过本文从源码的分析,我 ...

  8. kubernetes-1.18.2集群安装-02

    一.基础配置 修改主机名 # 在 172.17.32.23 上:hostnamectl set-hostname k8s-master01bash​# 在 172.17.32.38 上:hostnam ...

  9. MSSQL 指定分隔符号 生成数据集

    DECLARE @xml VARCHAR(MAX)='磨毛:1 缩率:2 干磨:3 湿摩:4 水洗牢度:5 手感:6 防水:7 PH:8 日晒:9' SET @xml= '<root>'+ ...

  10. 谈谈AQS

    AQS是什么? AQS全称叫AbstractQueuedSynchronizer,顾名思义,抽象的队列同步装置,在java中是一个抽象类.java JUC包下常用的同步类都是通过继承AQS实现的,那么 ...