XMU校外实训(一)

二进制密码锁

 

描述:

 

在海拉鲁大陆有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。

然而让人头疼的是,当按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。

当前密码锁状态已知,需要解决的问题是,林克至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。

输入

两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。

输出

至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。

 

输入样例 1 

011
000

输出样例 1

1


题解:

  当某一个按钮状态确定后,它的下一个按钮按与不按取决于这一个与目标状态是否一致,所以后续所有按钮其实都只取决于第一个按钮。

  枚举共两种情况:第一个按钮按(用1标记),第一个按钮不按(用0标记)

  最多次数为30次,故最终结果res初始化为31,用于判断impossible的情况

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     string init, result; // 要操作的,预期的
 7     string temp;         // 记录当前状态
 8     cin >> init >> result;
 9     int n = init.length(), res = 31; // 最多加30次
10     for (int i = 0; i < 2; ++i)
11     {
12         // 当前状态
13         temp = init;
14 
15         int next = i, times = 0;
16 
17         for (int j = 0; j < n; ++j)
18         {
19             if (next == 1)
20             {
21                 ///////////////////
22                 if (j > 0)
23                     temp[j - 1] ^= 1; //^1即实现取反的效果
24                 temp[j] ^= 1;
25                 if (j < n - 1)
26                     temp[j + 1] ^= 1;
27                 ///////////////////
28                 // 以上实现相邻3位取反(边缘为2位)
29 
30                 times++; // 操作次数加1
31             }
32             if (temp[j] == result[j]) // 若两位相同,则不用按下一位
33                 next = 0;
34             else // 若不同,则要按下一位
35                 next = 1;
36             if (temp == result) // 如果能达到预期结果
37             {
38                 res = min(res, times); // 记录最小操作数
39                 break;
40             }
41         }
42     }
43     if (res != 31)
44         cout << res;
45     else // 无法达到预期
46         cout << "impossible";
47 
48     return 0;
49 }

 

 题解:

  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 inline int read(int &s)
 19 {
 20     s = 0;
 21     int w = 1;
 22     char ch = getchar();
 23     while (ch < '0' || ch > '9')
 24     {
 25         if (ch == '-')
 26             w = -1;
 27         ch = getchar();
 28     }
 29     while (ch >= '0' && ch <= '9')
 30     {
 31         s = s * 10 + ch - '0';
 32         ch = getchar();
 33     }
 34     return s * w;
 35 }
 36 
 37 inline void write(int x)
 38 {
 39     if (x < 0)
 40     {
 41         putchar('-');
 42         x = -x;
 43     }
 44     if (x > 9)
 45         write(x / 10);
 46     putchar(x % 10 + '0');
 47 }
 48 bitset<6> start[5], result[5];
 49 bool turnoff(); // 关灯操作
 50 int main()
 51 {
 52     int t;
 53     int num = 1; // 第几组
 54     read(t);
 55     while (t--)
 56     {
 57         for (int i = 0; i < 5; ++i)
 58         {
 59             for (int j = 0; j < 6; ++j)
 60             {
 61                 int temp;
 62                 read(temp);
 63                 start[i][j] = temp;
 64             }
 65         }
 66 
 67         // 利用二进制枚举第一行64种状态 2^6
 68         // 只要确定第一行,则后面也随之确定
 69         for (int x = 0; x < 64; ++x)
 70         {
 71             result[0] = x; // result第一行会自动转化为二进制形态
 72             if (turnoff())
 73                 break;
 74         }
 75 
 76         // 输出结果
 77         cout << "PUZZLE #" << num << endl;
 78         for (int i = 0; i < 5; ++i)
 79         {
 80             for (int j = 0; j < 6; ++j)
 81             {
 82                 cout << result[i][j] << " ";
 83             }
 84             cout << endl;
 85         }
 86         ++num;
 87     }
 88 
 89     return 0;
 90 }
 91 
 92 // 执行熄灭操作
 93 bool turnoff()
 94 {
 95     bitset<6> temp[5];
 96     for (int i = 0; i < 5; ++i)
 97         temp[i] = start[i];
 98     // 用temp记录灯阵初始状态
 99 
100     for (int i = 0; i < 5; ++i)
101     {
102         // 根据result的第i行对temp的第i行进行操作
103         for (int j = 0; j < 6; ++j)
104         {
105             // 为1时按下
106             if (result[i][j] == 1)
107             {
108                 temp[i].flip(j); // temp的第i行j列取反
109                 // 竖直方向
110                 if (i != 4) // 若不是最后一行
111                     temp[i + 1].flip(j);
112                 if (i != 0) // 若不是第一行
113                     temp[i - 1].flip(j);
114                 // 水平方向
115                 if (j != 0)
116                     temp[i].flip(j - 1);
117                 if (j != 5)
118                     temp[i].flip(j + 1);
119             }
120         }
121         // 从temp的第i行判断下一行哪些需要按下
122         if (i < 4)
123         {
124             for (int j = 0; j < 6; ++j)
125             {
126                 if (temp[i][j])
127                     result[i + 1][j] = 1;
128                 else
129                     result[i + 1][j] = 0;
130             }
131         }
132         // 第5行时判断是否全熄灭
133         else
134             for (int j = 0; j < 6; ++j)
135                 if (temp[4][j] == 1)
136                     return 0;
137     }
138     return 1;
139 }

 

posted @ 2023-07-03 20:21  上原歩夢  阅读(71)  评论(0)    收藏  举报