You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

67 lines
2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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-125个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;
}