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

2 years ago
#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;
}
/* 我们需要知道某个局面是不是出现过,也就是需要把状态记录下来。
0125
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;
}