Files
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

67 lines
2.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma GCC optimize(2) // 累了就吸点氧吧~
#include <bits/stdc++.h>
using namespace std;
// 5858 ms
// 当前状态,当前到最终状态所需步数
unordered_map<int, int> step;
// 改变这个灯及其上下左右相邻的灯的状态
int turn(int t, int idx) { // idx从0开始
t ^= (1 << idx); // 改变第idx个灯,0->1,1->0,互换状态,其它灯不动
if (idx % 5) t ^= (1 << idx - 1); // 不为最左一列,将左侧灯改变
if (idx >= 5) t ^= (1 << idx - 5); // 不为最上一排,将上侧灯改变
if (idx < 20) t ^= (1 << idx + 5); // 不为最后一排,将下面灯改变
if (idx % 5 < 4) t ^= (1 << idx + 1); // 不为最后一列,将右面灯改变
return t;
}
/* 我们需要知道某个局面是不是出现过,也就是需要把状态记录下来。
而一个二维的数组状态不好记录,我们喜欢记录一维的。
每个位置不是0,就是1,最多25个格子,联想到状态压缩,用二进制来表示状态。
从输入的状态开始,走6步,可以覆盖到哪些数组状态呢?我们可以用状态压缩+Hash表记录下来,最终判断一下
int x = (1 << 25) - 1;这个状态是不是在Hash表中就行了。
也可以使用逆向思维:从最终状态逆序遍历,找出可以在6步之内到达最终状态的所有可行状态,应该是一样的
*/
void bfs() {
// 0-2^25-1(25个1),共2^25种状态
// 最终的状态 全都是 `11111`
int x = (1 << 25) - 1; // 左移 右移的优先级是最低的,比加减还要低。所以这里的括号是必需的
queue<int> q;
q.push(x);
step[x] = 0; // 记录这个状态是否出现过,如果出现过,是走几步出现的
while (q.size()) {
auto t = q.front();
q.pop();
if (step[t] == 6) break; // 反向最多扩展6步
for (int i = 0; i < 25; i++) {
x = turn(t, i); // u:当前状态,i:改变i这一位置,x:将此状态改变后的新状态
if (!step.count(x)) { // 过滤过出现过的状态,只要没有出现过的状态
step[x] = step[t] + 1;
q.push(x);
}
}
}
}
int main() {
// 预处理
bfs();
int T;
scanf("%d", &T);
while (T--) {
int g = 0; // g是地图
for (int i = 0; i < 25; i++) {
char c;
// 注意在scanf读取完一个整数,再次读取char时,要清空缓冲区,用" %c"解决
scanf(" %c", &c);
g += ((c - '0') << i); // 25个字符二进制压缩成数字
}
if (step.count(g) == 0)
puts("-1");
else
cout << step[g] << endl;
}
return 0;
}