pku_oj: W11-02 lights problem (C ++)

Problem Description:

It has a matrix of buttons, wherein each row has six buttons, a total of five lines, there is a position of each button on the lamp

When a button is pressed, the position of the button and the surrounding (upper, lower, left, right) light will change once 

If the lamp is lit originally, it will be extinguished

If the lamp is turned off, and will be illuminated 

Input:

Enter a case, case five rows, each row comprising six digits that are separated by spaces, can be 0 or 1.0 represents an initial state of the lamp is extinguished, the initial state of 1 indicates the lamp is lit . 

Output:

5 according to an input format of the output lines of the case, 1 indicates the need to press the corresponding button, 0 indicates no need to press the button corresponding to each number separated by a space.

Example 1:

Sample input:

 

 Sample output:

 

 Example 2:

Sample input:

 

 Sample output:

 

 analysis:

Analysis of the problem:

This problem requires us to be off by pressing the button lights, although there is no limit as many times as lamps, but only up to press time was significant (because second press of the same button will cancel the first press produced results, It is not equivalent to the press), and therefore,

Significantly press or not press. Secondly, the order would affect the button is pressed, there is a current state of an impact, no impact on the final result, explained later.

After analysis of the topic can be found, only a limited number of programs a variety of circumstances, that the solution space is limited, so consider using enumeration algorithm, then, to enumerate all the buttons case work?

- There are two states of a button (not pressed or pressed), a total of 6 * 5 = 30 switch, corresponding to the number of states is 2 ^ 30, is clearly very time consuming and undesirable.

Since the solution space is certain, we have no way to narrow the solution space?

The basic idea:

If there is a local state, once the local state is given, then the remaining several state can only be determined, so we only need to enumerate the local state.

Indeed, such local state does exist, such as the first row, when the state of the first row is determined, since our aim is that all lights are off, the first row is not extinguished lamp, only through the first two lines before it can be turned off, empathy, second line, third line ...

The fifth line is true, finally, according to the state of the fifth row to determine whether all the lights are off (because the first four lines followed by the guarantee are off line, only the fifth line can not be guaranteed), if true, then it got a valid solution, or continue to enumerate the next set of circumstances.

在这个方法中,我们只枚举第一行(事实上第一列也是可行的,且效率更高),状态数仅为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文件,为了调试的方便。

Guess you like

Origin www.cnblogs.com/laideng/p/11433017.html