枚举算法(熄灯问题)
上课笔记:图片截图自慕课网的视频
问题描述:
有一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都会改变一次。即,如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮改变3盏灯的状态;在矩阵边上的按钮改变4盏灯的状态;其他的按钮改变5盏灯的状态。
请你写一个程序,确定需要按下哪些按钮,恰好使得所有的灯都熄灭。
输入输出描述:
解题思路:
首先分析:根据上述的规则我们可以得出
- 第2次按下同一个按钮时,将抵消第1次按下时所产生的结果。因此,每个按钮最多只需要按下一次;
- 各个按钮被按下的顺序对最终的结果没有影响;
- 对第1行中每盏点亮的灯,按下第2行对应的按钮,就可以熄灭第1行的全部灯。如此重复下去,可以熄灭第1、2、3、4行的全部灯。同样,按下第1、2、3、4、5列的按钮,可以熄灭前5列的灯。
第一想法:枚举所有可能的按钮(开关)状态,对每个状态计算最后灯的情况,看是否都熄灭;但是,一共有30个开关,那么状态数2的30次方,太大,会超时
第二想法:我们可不可以找到某个局部
。只要这个局部
能够确定下来,整个30个灯的状态就可以确定
。我们就可以很明显的发现,第一行
就是这样的局部,来简单分析一下:
所以:我们只需枚举第一行的状态,状态数就是2的6次方=64
在用代码实现的时候可以使用的一些方法:
1、首先解决的问题就是把灯以及开关的状态存起来(这里我们可以使用一个char类型的一位数组来存)
2、0代表关,1代表开。可以利用二进制进行枚举
;由k位的“0”“1”组成的组合,这个组合可以与int类型的(0到2的k次方 -1)2的k次方个数一一对应。