pku_oj: W11-02熄灯问题(C++)

问题描述:

有一个由按钮组成的矩阵, 其中每行有6个按钮, 共5行,每个按钮的位置上有一盏灯

当按下一个按钮后, 该按钮以及周围位置(上边, 下边, 左 边, 右边)的灯都会改变一次

如果灯原来是点亮的, 就会被熄灭

如果灯原来是熄灭的, 则会被点亮

输入:

输入一个案例,案例由5行组成, 每一行包括6个数字,这些数字以空格隔开, 可以是0或1。0 表示灯的初始状态是熄灭的,1 表示灯的初始状态是点亮的。

输出:

按照该案例的输入格式输出5行 ,1 表示需要把对应的按钮按下,0 表示不需要按对应的按钮,每个数字以一个空格隔开 。

示例1:

样例输入:

样例输出:

 示例2:

样例输入:

样例输出:

 分析:

对问题的分析:

本题要求我们通过按按钮来熄灭灯,虽然按灯的次数没有限制,但只有最多按一次是有意义的(因为第二次按下同一按钮,将会抵消第一次按下所产生的结果,等价于不按),因此,

有意义的是 按一次 或者 不按。其次,按钮按下的顺序是否有影响,有当前状态有影响,对最终结果无影响,稍后解释。

经过对题目的分析,可以发现,方案数只有有限多种情况,即解空间是有限的,因而可以考虑采用枚举算法,那么,枚举所有按钮情况是否可行呢?

——一个按钮有两种状态(按下或不按下),一共有5*6 = 30个开关,对应状态数为2^30,显然非常耗时,不可取。

既然解空间是一定的,我们有没有办法缩小解空间呢?

基本思路:

如果存在一个局部状态,一旦这个局部状态给定了,那么剩余状态只能是确定的若干种,如此,我们只需枚举这个局部的状态。

事实上,这样的局部状态是确实存在的,比如第一行,当第一行的状态确定后,由于我们的目的是将所有灯都熄灭,对于第一行中未熄灭的灯,只有通过第二行才能将其熄灭,同理,第二行、第三行...

第五行都是如此,最后,根据第五行的状态来判定是否所有灯都已熄灭(因为前四行都由其后一行保证均熄灭,只有第五行无法保证),如果成立,则得到了一个有效解,否则继续枚举下一组情况。

在这个方法中,我们只枚举第一行(事实上第一列也是可行的,且效率更高),状态数仅为2^6=64种,在效率上足以令人满意。

实现方法:

首先建立两个二维矩阵,用于存储puzzle(灯的初始状态)和press(按钮的状态),为了简化矩阵左右上下边界的代码量以及index与序号对应,将矩阵从5*6扩充为6*8,并初始化为0。

接着,我们需要枚举第一行的所有情况,传统的办法是写6个for循环,但这显然不是个好办法(比如矩阵是100列),观察发现,矩阵中每一个元素的取值只能是0/1,对第一行整体观察,其取值范围为

从000 000,到111 111(二进制),对应于十进制的0到63,因此,我们可以枚举一个整型变量,它从0自增到63,然后用位运算分解赋到相应的位置。

对于枚举的每一种情况,都要判断该情况是否可行,具体方法是,由于第一行的状态已经由分解给定,逐行分析第2行到第5行,最后判断第5行的puzzle是否为全0,如果是则输出press并返回,

否则继续枚举下一组情况,如果枚举了全部情况但不存在解,则输出“无解”。

代码(c++):

 1 #include <iostream>
 2 #include <string.h>
 3 using namespace std;
 4 int puzzle[6][8] = {0};
 5 int puzzle_copy[6][8];
 6 int press[6][8] = {0};
 7 void Initialize();        //对puzzle初始化
 8 void Breakdown(int);    //分解整型变量,并赋给相应位置
 9 bool Guess();            //测试当前分解情况是否可行,可行则返回true,否则返回false
10 void Execute(int, int);        //执行第i行第j列按下操作
11 void Print();            //打印Press矩阵
12 int main()
13 {
14     Initialize();
15     int i;
16     for (i = 0; i < 64; ++i) {
17         memcpy(puzzle, puzzle_copy, sizeof(puzzle));
18         Breakdown(i);
19         if (Guess()) {
20             Print();
21             break;
22         }
23     }
24     if (i == 64)
25         cout << "无解\n" << endl;
26     return 0;
27 }
28
29 void Initialize()
30 {
31     //用户输入5*6矩阵
32     freopen("input.txt", "r", stdin);
33     for (int i = 1; i < 6; ++i)
34         for (int j = 1; j < 7; ++j)
35             cin >> puzzle[i][j];
36     memcpy(puzzle_copy, puzzle, sizeof(puzzle));
37 }
38
39 void Breakdown(int x)
40 {
41     int i = 6;
42     while (x > 0) {
43         press[1][i] = x & 1;
44         Execute(1, i--);
45         x >>= 1;
46     }
47 }
48
49 bool Guess()
50 {
51     for (int i = 2; i < 6; ++i) {
52         for (int j = 1; j < 7; ++j) {
53             if (puzzle[i - 1][j] == 1) {
54                 press[i][j] = 1;
55                 Execute(i, j);
56             }
57             else
58                 press[i][j] = 0;
59         }
60     }
61     for (int i = 1; i < 7; ++i) {
62         if (puzzle[5][i] == 1)
63             return false;
64     }
65     return true;
66 }
67
68 void Execute(int i, int j)
69 {
70         if (press[i][j] == 1) {
71             puzzle[i][j] ^= 1;        //取反
72             puzzle[i - 1][j] ^= 1;
73             puzzle[i][j - 1] ^= 1;
74             puzzle[i][j + 1] ^= 1;
75             puzzle[i + 1][j] ^= 1;
76         }
77 }
78
79 void Print()
80 {
81     cout << "press结果为:" << endl;
82     for (int i = 1; i < 6; ++i) {
83         for (int j = 1; j < 7; ++j) {
84             cout << press[i][j] << ‘ ‘;
85         }
86         cout << endl;
87     }
88 }

注意:这里的输入流重定向到了input.txt文件,为了调试的方便。

原文地址:https://www.cnblogs.com/laideng/p/11433017.html

时间: 2024-10-31 03:06:07

pku_oj: W11-02熄灯问题(C++)的相关文章

百度刚放假啊数据库风口浪尖萨拉疯了

http://www.ebay.com/cln/l_x5585/2015.02.11/176746639012 http://www.ebay.com/cln/jiacha_boryk/2015.02.11/176837188016 http://www.ebay.com/cln/gbnlin0/2015.02.11/176837189016 http://www.ebay.com/cln/j_j2841/2015.02.11/177066749015 http://www.ebay.com/c

百度房间爱师傅卡卡是快乐疯了;爱死

http://www.ebay.com/cln/shx9479/-/177007606013/2015.02.11 http://www.ebay.com/cln/genqi12/-/176846034010/2015.02.11 http://www.ebay.com/cln/seyyon2/-/176906811016/2015.02.11 http://www.ebay.com/cln/wcn5971/-/176846032010/2015.02.11 http://www.ebay.co

百度和房价是否健康教案上开发

http://www.ebay.com/cln/l.kuan2/-/167247714018/2015.02.10 http://www.ebay.com/cln/setlia-3616/-/167086016019/2015.02.10 http://www.ebay.com/cln/pen-y77/-/167086017019/2015.02.10 http://www.ebay.com/cln/yua-me2/-/167399441016/2015.02.10 http://www.eba

百度电话费健身房拉伸件礼服加拉斯减肥

http://www.ebay.com/cln/cnli_c90nphs5e/-/167379958016/2015.02.07 http://www.ebay.com/cln/gaw4612/-/167226239018/2015.02.07 http://www.ebay.com/cln/re_len4/-/167263594010/2015.02.07 http://www.ebay.com/cln/ta.ku83/-/167162702017/2015.02.07 http://www.

百度回复金卡是减肥拉进来收付款

http://www.ebay.com/cln/cnli_c90nphs5e/-/167379958016/2015.02.08 http://www.ebay.com/cln/gaw4612/-/167226239018/2015.02.08 http://www.ebay.com/cln/re_len4/-/167263594010/2015.02.08 http://www.ebay.com/cln/ta.ku83/-/167162702017/2015.02.08 http://www.

百度放假哈萨克就发了设计费拉萨

http://www.ebay.com/cln/ldicn.mz6dm/2015.02.11/177030163015 http://www.ebay.com/cln/tan_qi5/2015.02.11/176903144013 http://www.ebay.com/cln/l.lu104/2015.02.11/177030175015 http://www.ebay.com/cln/ya01191/2015.02.11/176722580014 http://www.ebay.com/cl

百度房间撒谎发卡上就发了空间啊

http://www.ebay.com/cln/h-h4129/2015.02.11/176819191016 http://www.ebay.com/cln/fendo88/2015.02.11/176613943017 http://www.ebay.com/cln/ygon288/2015.02.11/176727517018 http://www.ebay.com/cln/ta.ch17/2015.02.11/176613950017 http://www.ebay.com/cln/g-

百度房间沙发客服就考试考几分离开

http://www.ebay.com/cln/jinlon8/book/167309734010/2015.02.10 http://www.ebay.com/cln/bam5330/book/167115292019/2015.02.10 http://www.ebay.com/cln/yi_za70/book/167315676012/2015.02.10 http://www.ebay.com/cln/y.y3463/book/167285977014/2015.02.10 http:/

Web Service学习笔记之----JAX-RPC

众所周知,数据科学是这几年才火起来的概念,而应运而生的数据科学家(data scientist)明显缺乏清晰的录取标准和工作内容.此次课程以<星际争霸II>回放文件分析为例,集中在IBM Cloud相关数据分析服务的应用.面对星际游戏爱好者希望提升技能的要求,我们使用IBM Data Science Experience中的jJupyter Notebooks来实现数据的可视化以及对数据进行深度分析,并最终存储到IBM Cloudant中.这是个介绍+动手实践的教程,参会者不仅将和讲师一起在线