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 }

浙公网安备 33010602011771号