• 枚举--熄灯问题


    – 有一个由按钮组成的矩阵, 其中每行有6个按钮, 共5行
    – 每个按钮的位置上有一盏灯
    – 当按下一个按钮后, 该按钮以及周围位置(上边, 下边, 左边, 右边)的灯都会改变状态

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

    – 如果灯原来是熄灭的, 则会被点亮
    • 在矩阵角上的按钮改变3盏灯的状态
    • 在矩阵边上的按钮改变4盏灯的状态
    • 其他的按钮改变5盏灯的状态

    与一盏灯毗邻的多个按钮被按下时,一个操作会抵消另一次操作的结果
     给定矩阵中每盏灯的初始状态,求一种按按钮方案,使得所有的灯都熄灭

    输入:
    – 第一行是一个正整数N, 表示需要解决的案例数
    – 每个案例由5行组成, 每一行包括6个数字
    – 这些数字以空格隔开, 可以是0或1
    – 0 表示灯的初始状态是熄灭的
    – 1 表示灯的初始状态是点亮的

     输出:
    – 对每个案例, 首先输出一行,
    输出字符串 “PUZZLE #m”, 其中m是该案例的序

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

    测试样例:

    输入:

    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

    输出:

    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

    解题思路:

    第2次按下同一个按钮时,
    将抵消第1次按下时所产生的结果

    第2次按下同一个按钮时,
    将抵消第1次按下时所产生的结果
    每个按钮最多只需要按下一次

    • 第2次按下同一个按钮时,
    将抵消第1次按下时所产生的结果
    每个按钮最多只需要按下一次
    • 各个按钮被按下的顺序对最终的结果没有影响

    • 第2次按下同一个按钮时,
    将抵消第1次按下时所产生的结果
    每个按钮最多只需要按下一次
    • 各个按钮被按下的顺序对最终的结果没有影响
    • 对第1行中每盏点亮的灯, 按下第2行对应的按钮, 就可以熄灭第1行的全部灯
    • 如此重复下去, 可以熄灭第1, 2, 3, 4行的全部灯

    经过观察, 发现第1行就是这样的一个 “局部”
    – 因为第1行的各开关状态确定的情况下, 这些开关作用过后, 将导致第1行某些灯是亮的, 某些灯是灭的

    要熄灭第1行某个亮着的灯(假设位于第i列), 那么唯一的办法就是按下第2行第i列的开关

    (因为第1行的开关已经用过了, 而第3行及其后的开关不会影响到第1行)

    – 为了使第1行的灯全部熄灭, 第2行的合理开关状态就是唯一的• 第2行的开关起作用后,为了熄灭第2行的灯, 第3行的合理开关状态就也是唯一的

     以此类推, 最后一行的开关状态也是唯一的
    • 只要第1行的状态定下来, 记作A, 那么剩余行的情况就是确定唯一的了

    推算出最后一行的开关状态, 然后看看最后一行的开关起作用后,最后一行的所有灯是否都熄灭:
    • 如果是, 那么A就是一个解的状态
    • 如果不是, 那么A不是解的状态, 第1行换个状态重新试试
    • 只需枚举第1行的状态, 状态数是2的6次方  = 64

    关键记住这点:当前行灯的状态是下一行的按钮按下的方案,因为下一行按此方案,才能保证当前行的灯都熄灭。

    此测试数据:

    输入灯的第1组测试数据
    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
    需要逐行输入,后续再进行优化,稍微有点麻烦,抱歉了!大家也可以自己优化。

    python代码如下:

      1 #print("{0:b}".format(3))
      2 #print(bin(5).replace('0b',''))
      3 #print(int("011010",2)) 26
      4 #print(int("100111",2)) 39
      5 #print(int("001001",2)) 9
      6 #print(int("100101",2)) 37
      7 #print(int("011100",2)) 28
      8 #print(int("101001",2)) 41
      9 #print(int("110101",2)) 53
     10 #print(int("100111",2)) 39
     11 #print(bin(5))
     12 #print(type(bin(5).replace('0b','')))
     13 #print(int(bin(5).replace('0b',''))>>2)
     14 #print(bin(5))
     15 #print(39 ^ (1 << 1))
     16 #print(bin(39^(1<<1)))
     17 #print(bin(4))
     18 #print((5 >> 2) & 0)
     19 #m = "00220202020202020222000200"
     20 #print(''.join(["%s " % i for i in m]))
     21 """
     22 输入灯的第1组测试数据
     23 0 1 1 0 1 0
     24 1 0 0 1 1 1
     25 0 0 1 0 0 1
     26 1 0 0 1 0 1
     27 0 1 1 1 0 0
     28 
     29 输出按灯的方案
     30 1 0 1 0 0 1
     31 1 1 0 1 0 1
     32 0 0 1 0 1 1
     33 1 0 0 1 0 0
     34 0 1 0 0 0 0
     35 
     36 输入灯的第2组测试数据
     37 0 0 1 0 1 0
     38 1 0 1 0 1 1
     39 0 0 1 0 1 1
     40 1 0 1 1 0 0
     41 0 1 0 1 0 0
     42 
     43 输出按灯的方案:
     44 1 0 0 1 1 1
     45 1 1 0 0 0 0
     46 0 0 0 1 0 0
     47 1 1 0 1 0 1
     48 1 0 1 1 0 1
     49 """
     50 
     51 oriLight = [0 for i in range(0,5)] #输入灯的矩阵,一个比特表示一盏灯,初始化为[0,0,0,0,0]这样的List
     52 lights = [0 for i in range(0,5)] #不停变化的灯矩阵
     53 result = [0 for i in range(0,5)] #结果开关矩阵
     54 switchs=0  #某一行的开关状态
     55 
     56 #定义读入命令行输入数据的函数
     57 def ReadInitData():
     58     i = 0
     59     print("请输入每盏灯的初始数据,每盏灯空格间隔:")
     60     while (i < 5):
     61         line = input()
     62         oriLight[i] = int(line.replace(" ", ""), 2)
     63         i = i + 1
     64 
     65 #获取输入值转化为二进制,然后去第ilocation位置的值
     66 def GetBit(iData,ilocation):
     67     #print(iData>>ilocation)
     68     rtn = (iData >> ilocation) & 1
     69     return  rtn
     70 
     71 def Flip(iData,ilocation):
     72     iData = iData ^ (1 << ilocation)
     73     return iData
     74 
     75 def OutPutResult(list):
     76     print("所有灯都熄灭的按下方案为:
    ")
     77     for i in list:
     78         #首先整数转二进制,然后去除0b开头的字符,最后zfill函数,保证6个长度,不够,前面补0
     79         tempStr = bin(i).replace('0b','').zfill(6)
     80         #遍历,给每个字符串中的字符增加空格
     81         print("".join(["%s " % t for t in tempStr]))
     82         #for t in tempStr:
     83             #print(t,end=" ")
     84         #print("")
     85 def main():
     86 
     87     #读取输入灯的初始数据,然后存入oriLight列表中
     88     ReadInitData()
     89     #遍历首行开关的64种状态,每个整型值的二进制值代表第一行其中一组按下方案
     90     n = 0
     91     while (n<64):
     92         # 每次循环前,都把输入灯的初始数据重新给变化的lights赋值
     93         #lights = oriLight这里提醒大家不要这样写,如果这样写了,lights的变化会影响oriLight的变化,它们指向同一块地址
     94         #这里使用的是浅拷贝copy.copy(a),为了更加保险,也可以使用深拷贝copy.deepcopy(a)
     95         lights = oriLight[:]
     96         #遍历针对第一行的64种变化方案给swiths赋值
     97         switchs = n
     98         for i in range(5):
     99             result[i] = switchs; #第i行的开关方案
    100             for j in range(6):
    101                 #如果switchs二进制中,值是1的表示按下,需要处理周围几盏灯的状态,如果值是0,则不处理
    102                 if (GetBit(switchs,j)) :
    103                     #首先修改按下按钮本身自己灯的状态
    104                     lights[i] = Flip(lights[i], j);
    105                     #j表示列,如果是小于第5列,才需要修改按下按钮左边的灯状态,从右往左方向,第0列在最右边
    106                     if j < 5 :
    107                         lights[i] = Flip(lights[i], j + 1)  #改左灯的状态
    108                     # j表示列,如果是大于第0列,才需要修改按下按钮右边的灯状态
    109                     if j > 0 :
    110                         lights[i] = Flip(lights[i],j - 1) #修改右灯的状态
    111 
    112             if (i < 4):
    113                 # 通过异或运算符,修改按下按钮的下面方向的按钮灯的状态,1^0,值1灯亮,1^1,值0灯熄灭
    114                 lights[i + 1] ^= switchs
    115             # 第i行灯情况确定第i + 1行开关方案,因为我们需要把第i行亮的灯都熄灭,那么i+1行的哪些按钮按下的方案就确定下来了
    116             switchs = lights[i]
    117 
    118         #假设成立,说明第5行的灯都灭了,然后输出该按钮按下方案
    119         if (lights[4] == 0):
    120             OutPutResult(result)
    121             #print(n)
    122             break
    123         n += 1
    124 
    125 if __name__=="__main__":
    126     main()
    View Code
  • 相关阅读:
    【Comet OJ Contest #15】孤独的吉姆 6
    【SSLOJ1467】U
    【SSLOJ1471】Y
    ajax调用webService
    泛型
    windows Server 2003 FTP
    ajax
    Linq 执行概念
    15款提高工作效率的工具分享
    Scrum是一种迭代式增量软件开发过程,通常用于敏捷软件开发
  • 原文地址:https://www.cnblogs.com/an-wl/p/12287961.html
Copyright © 2020-2023  润新知