枚举算法实例应用(二)
Extended Lights Out
Description
In an extended version of the game Lights Out, is a puzzle with 5 rows of 6 buttons each (the actual puzzle has 5 rows of 5 buttons each). Each button has a light. When a button is pressed, that button and each of its (up to four) neighbors above, below, right and left, has the state of its light reversed. (If on, the light is turned off; if off, the light is turned on.) Buttons in the corners change the state of 3 buttons; buttons on an edge change the state of 4 buttons and other buttons change the state of 5. For example, if the buttons marked X on the left below were to be pressed,the display would change to the image on the right.
The aim of the game is, starting from any initial set of lights on in the display, to press buttons to get the display to a state where all lights are off. When adjacent buttons are pressed, the action of one button can undo the effect of another. For instance, in the display below, pressing buttons marked X in the left display results in the right display. Note that the buttons in row 2 column 3 and row 2 column 5 both change the state of the button in row 2 column 4,so that, in the end, its state is unchanged.
Note:
- It does not matter what order the buttons are pressed.
- If a button is pressed a second time, it exactly cancels the effect of the first press, so no button ever need be pressed more than once.
- As illustrated in the second diagram, all the lights in the first row may be turned off, by pressing the corresponding buttons in the second row. By repeating this process in each row, all the lights in the first four rows may be turned out. Similarly, by pressing buttons in columns 2, 3, all lights in the first 5 columns may be turned off. Write a program to solve the puzzle.
Input
The first line of the input is a positive integer n which is the number of puzzles that follow. Each puzzle will be five lines, each of which has six 0 or 1 separated by one or more spaces. A 0 indicates that the light is off, while a 1 indicates that the light is on initially.
Output
For each puzzle, the output consists of a line with the string: “PUZZLE #m”, where m is the index of the puzzle in the input file. Following that line, is a puzzle-like display (in the same format as the input) . In this case, 1’s indicate buttons that must be pressed to solve the puzzle, while 0 indicate buttons, which are not pressed. There should be exactly one space between each 0 or 1 in the output puzzle-like display.
Sample Input
2
0 1 1 0 1 0
1 0 0 1 1 1
0 0 1 0 0 1
1 0 0 1 0 1
0 1 1 1 0 0
0 0 1 0 1 0
1 0 1 0 1 1
0 0 1 0 1 1
1 0 1 1 0 0
0 1 0 1 0 0
Sample Output
PUZZLE #1
1 0 1 0 0 1
1 1 0 1 0 1
0 0 1 0 1 1
1 0 0 1 0 0
0 1 0 0 0 0
PUZZLE #2
1 0 0 1 1 1
1 1 0 0 0 0
0 0 0 1 0 0
1 1 0 1 0 1
1 0 1 1 0 1
题设分析:
根据题设可分析出以下两种潜在的规定:
- 开关按下的先后顺序与结果的正确性无关,即先按哪个后按哪个不改变最后一个开关按下时灯的亮灭情况。
- 每一个按钮按下多次时,将抵消前面按下时所产生的结果,即某按钮按下两次,将恢复至初始状态,即未按下按钮状态。所以按钮只有按下和没有按下两种情况,不妨用0表示没有按下,1表示按下。
解题分析:
-
枚举,即暴力破解。第一想法自然是枚举所有可能的开关状态,对每一个状态计算一下最后的灯的亮灭情况,若均熄灭则表示该状态为解。
-
每个开关有且仅有两种状态,且开关矩阵为5×6的矩阵,共30个开关,所以一共有 2 30 2^{30} 230种可能的解,是一个相当大的数据量。所以应考虑剪枝,以期减少枚举的轮次。
-
不难想到,枚举一个“局部”,当局部被确定时,剩下的部分也随之确定,不可能发生变化,所以我们只需枚举确定的局部可能的情况即可,以此来极大程度上减少枚举的轮次。
-
而通过开关操作事第一行全部熄灭就是这样的一个局部。如:当按下若干开关使得第一行灯全部熄灭,开关会使第二行该开关下面的灯的亮灭情况翻转,所以,第二行的开关按动方案也随之确定,即将第二行仍然亮着的灯的开关按下,至此第一、二行全部熄灭一次类推,而当按下第三行的开关时,并不会影响第一行灯的亮灭。
-
所以,若按此方式到第五行开关完成按动之后第五行灯为全部熄灭状态则表明该第一行的局部是可行的,即找到一个解。若第5行开关按动完成之后后仍有未熄灭的灯,则表明以该第一行为局部的解是不可行方案,因此抛弃之,进行下一个第一行状态的试探直至出现第一个可行的方案即为解。
-
综上,只需以第一行的 2 6 2^6 26种方案为局部进行 2 6 2^6 26次枚举即可。
假若以int数组来存储灯源矩阵,当灯源矩阵规模足够大时,int数组占用空间大的劣势就体现出来了。
因此考虑数据类型的内存占用问题:
-
int类型占用4B(字节)的内存大小,共4*8=32位,有符号数可表示 − 2