熄灯问题

 

题解:

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cmath>
  5 #include <cstring>
  6 #include <vector>
  7 #include <map>
  8 #include <stack>
  9 #include <queue>
 10 #include <deque>
 11 #include <list>
 12 #include <set>
 13 #include <cctype>
 14 #include <bitset>
 15 
 16 using namespace std;
 17 
 18 bitset<6> start[5], result[5];
 19 bool turnoff(); // 关灯操作
 20 int main()
 21 {
 22     int t;
 23     int num = 1; // 第几组
 24     cin >> t;
 25     while (t--)
 26     {
 27         for (int i = 0; i < 5; ++i)
 28         {
 29             for (int j = 0; j < 6; ++j)
 30             {
 31                 int temp;
 32                 cin >> temp;
 33                 start[i][j] = temp;
 34             }
 35         }
 36 
 37         // 利用二进制枚举第一行64种状态 2^6
 38         // 只要确定第一行,则后面也随之确定
 39         for (int x = 0; x < 64; ++x)
 40         {
 41             result[0] = x; // result第一行会自动转化为二进制形态
 42             if (turnoff())
 43                 break;
 44         }
 45 
 46         // 输出结果
 47         cout << "PUZZLE #" << num << endl;
 48         for (int i = 0; i < 5; ++i)
 49         {
 50             for (int j = 0; j < 6; ++j)
 51             {
 52                 cout << result[i][j] << " ";
 53             }
 54             cout << endl;
 55         }
 56         ++num;
 57     }
 58 
 59     return 0;
 60 }
 61 
 62 // 执行熄灭操作
 63 bool turnoff()
 64 {
 65     bitset<6> temp[5];
 66     for (int i = 0; i < 5; ++i)
 67         temp[i] = start[i];
 68     // 用temp记录灯阵初始状态
 69 
 70     for (int i = 0; i < 5; ++i)
 71     {
 72         // 根据result的第i行对temp的第i行进行操作
 73         for (int j = 0; j < 6; ++j)
 74         {
 75             // 为1时按下
 76             if (result[i][j] == 1)
 77             {
 78                 temp[i].flip(j); // temp的第i行j列取反
 79                 // 竖直方向
 80                 if (i != 4) // 若不是最后一行
 81                     temp[i + 1].flip(j);
 82                 if (i != 0) // 若不是第一行
 83                     temp[i - 1].flip(j);
 84                 // 水平方向
 85                 if (j != 0)
 86                     temp[i].flip(j - 1);
 87                 if (j != 5)
 88                     temp[i].flip(j + 1);
 89             }
 90         }
 91         // 从temp的第i行判断下一行哪些需要按下
 92         if (i < 4)
 93         {
 94             for (int j = 0; j < 6; ++j)
 95             {
 96                 if (temp[i][j])
 97                     result[i + 1][j] = 1;
 98                 else
 99                     result[i + 1][j] = 0;
100             }
101         }
102         // 第5行时判断是否全熄灭
103         else
104             for (int j = 0; j < 6; ++j)
105                 if (temp[4][j] == 1)
106                     return 0;
107     }
108     return 1;
109 }

 

 

python代码:

 1 def turnoff(start, result):
 2     temp = start.copy()  # 用来临时储存原灯阵start
 3     for i in range(5):
 4         for j in range(6):
 5             if result[i] & (1 << j):  # 如果result[i]的第j位数字为1(按下了),则改变其他按钮状态
 6                 temp[i] ^= (1 << j)
 7                 # 下面是边界条件判断
 8                 if i != 4:
 9                     temp[i+1] ^= (1 << j)
10                 if i != 0:
11                     temp[i-1] ^= (1 << j)
12                 if j != 0:
13                     temp[i] ^= (1 << j - 1)
14                 if j != 5:
15                     temp[i] ^= (1 << j + 1)
16         if i < 4:  # 不是最后一行
17             result[i+1] = temp[i]
18         # 以temp的上一行表示 result的下一行是否按下,例如
19         # 1 0 1 1 0 1
20         # 0 0 0 0 0 0
21         # 0 0 0 0 0 0
22         # 0 0 0 0 0 0
23         # 0 0 0 0 0 0
24         # 第一行若为1,则要按下第二行对应列的按钮
25         else:
26             if temp[4] != 0:  # 若最后一行没有全部熄灭,则该方法无法熄灭全部
27                 return False
28     return True
29 
30 
31 t = int(input())
32 num = 1
33 for _ in range(t):
34     start = []
35     for _ in range(5):
36         row = int(''.join(input().split()), 2)
37         # 将输入的二进制字符串转换为二进制整数,中间不间隔
38 
39         start.append(row)  # start中每个元素表示了 **一行灯的状态(是否亮着)**(用一个二进制数表示),5个表示五行
40     result = [0] * 5  # result中每个元素表示了 **一行灯的状态(是否按下)**(用一个二进制数表示),5个表示五行
41     for x in range(64):  # 枚举第一行的64种状态(2^6)(因为第一行状态若确定了,则后面的状态也随之确定)
42         result[0] = x
43         if turnoff(start, result):
44             break
45     print('PUZZLE #{}'.format(num))
46     for i in range(5):
47         row_str = bin(result[i])[2:].zfill(6)  # 二进制数格式如 0b1011,则应该舍去前两位0b
48         # 将整数转换为二进制字符串,并在左边补齐0,使其总长度为6
49 
50         row = ' '.join(str(x) for x in row_str)
51         print(row, end=' ')  # 注意数字末尾有空格
52         print()
53     num += 1

 

posted @ 2023-07-11 23:02  上原歩夢  阅读(32)  评论(0)    收藏  举报