刷Python算法题第9天,想要分享的东西提上日程...🌈 接受失败而不气馁才是对勇气最大的考验。
问题描述:有一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都会改变一次。即如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮改变3盏灯的状态;在矩阵边上的按钮改变4盏灯的状态;其他的按钮改变5盏灯的状态。例如在图1中,左边矩阵中用X标记的按钮表示被按下,右边的矩阵表示灯状态的改变。对矩阵中的每一盏灯设置一个初始状态。请你按按钮,直至每一盏灯都熄灭。与每一盏灯毗邻的多个按钮被按下时,一次操作会抵消另一次操作的结果。
图1
在图2中,第2行第3、5列的按钮都被按下,因此第2行、第4列的灯的状态就不会发生改变。
图2
请你写一个程序,确定需要按下哪些按钮,恰好使得所有的灯都被熄灭。
输入:5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个逗号隔开。0表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。
输出:5行组成,每一行包括6个数字(0或1)。 相邻两个数字之间用单个空格隔开。其中的1表示需要把对应的按钮按下,0则表示不需要按对应的按钮。
import numpy as np
line = [[0] * 6] * 5
for i in range(5):
line[i] = input("请输入第" + str(i) + "行: ").split(',')
# 将line中的元素转换为整型
line[i] = list(map(int, line[i]))
puzzle = np.array(line)
zero = np.zeros(6)
# 向puzzle中的最上面加入一行0
puzzle = np.insert(puzzle, 0, values=zero, axis=0)
# 向puzzle中的最后一列加入一列0
puzzle = np.insert(puzzle, 6, values=zero, axis=1)
# 向puzzle中的第0列加入一列0
puzzle = np.insert(puzzle, 0, values=zero, axis=1)
b = [[0 for col in range(8)] for row in range(6)] # 创建6*8矩阵,6和8注意不要写反
press = np.array(b)
# 以上两句或者之间写为 press = np.zero(6,8)
def guess():
for r in range(1, 5):
for c in range(1, 7):
# 根据press的第一行和puzzle的第一行,确定press其他行
press[r+1][c] = (puzzle[r][c] + press[r][c] + press[r-1][c] + press[r][c-1] + press[r][c+1]) % 2
# 判断所计算的press能否熄灭最后一行的所有灯,是则返回1,否则返回0
for c in range(1, 7):
if (press[5][c-1] + press[5][c] + press[5][c+1] + press[4][c]) % 2 != puzzle[5][c]:
return 0
return 1
# 枚举第一行按下开关的所有可能性,有2^6个
def enumeration():
while guess() == 0: # 如果最后一行不熄灭所有的灯,将持续循环
press[1][1] += 1 # 按下(1,1)位置的灯
c = 1
while(press[1][c] >1): # 如果(1,c)的灯大于1,证明多按了一次,恢复熄灭状态
press[1][c] = 0
c +=1
press[1][c] +=1
enumeration()
print("灯的初始状态:\n", puzzle[1:6, 1:7])
print("按下结果为:\n", press[1:6, 1:7])
代码思路:
当按下第一行的按钮,对于第一行仍亮着的灯,由第二行按钮控制,以此类推,前四行同理,第五行如果全部熄灭,则第一行按钮的方式正确,否则,换一种第一行按钮按下的方式。对于初始矩阵(5*6),第一行按钮按下的状态有2^6(64)种。
灯最后的状态(是否按下一行开关之前)与自身的状态、上、左、右按钮的操作有关,考虑到两次操作会抵消,则求他们操作的和与2的余数,为0,则熄灭,为1,则亮灯。