题目描述
在一个 5 × 5 5×5 5×5的棋盘上有 12 12 12个白色的骑士和 12 12 12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为 1 1 1,纵坐标相差为 2 2 2或者横坐标相差为 2 2 2,纵坐标相差为 1 1 1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。
输入格式
第一行有一个正整数 T ( T < = 10 ) T(T<=10) T(T<=10),表示一共有 T T T组数据。接下来有 T T T个 5 × 5 5×5 5×5的矩阵, 0 0 0表示白色骑士, 1 1 1表示黑色骑士, ∗ * ∗表示空位。两组数据之间没有空行。
输出格式
对于每组数据都输出一行。如果能在 15 15 15步以内(包括 15 15 15步)到达目标状态,则输出步数,否则输出 − 1 -1 −1。
样例输入
2
2
2
10110
10110
10110
01
∗
11
01*11
01∗11
10111
10111
10111
01001
01001
01001
00000
00000
00000
01011
01011
01011
110
∗
1
110*1
110∗1
01110
01110
01110
01010
01010
01010
00100
00100
00100
样例输出
7
7
7
−
1
-1
−1
听说正解是
I
D
A
∗
IDA^*
IDA∗,写
I
D
A
∗
IDA^*
IDA∗是不可能的,这辈子都不可能的,因此只能靠双向深搜
+
m
e
e
t
i
n
t
h
e
m
i
d
d
l
e
+meet\ in\ the\ middle
+meet in the middle过日子了。
显然直接暴搜
15
15
15层会
T
L
E
TLE
TLE,那么换个思路。
既然起点和终点都是已知的,不妨双向搜索,从起点搜
8
8
8步,终点搜
7
7
7步,在判断一下有没有可以拼起来的。
众所周知,深搜的状态数与层数成指数级增长,那么层数减半,状态数也就不会太多了 (实测只有几十万种)。
所以我们就可以放心大胆的搜了。
由于每个点至多只有
3
3
3种取值,而总共只有
25
25
25个格子,因此可以直接用三进制表示整个矩阵 考试的时候用二维矩阵单哈直接冲突,嗯,难受。
将从终点出发的状态按照
h
a
s
h
hash
hash值为第一关键字,步数为第二关键字排序,之后每个从起点出发的状态就可以去这里面二分找最少的步数了 (懒得去重,所以直接找最左边的位置)。
C o d e Code Code
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX_P1 = 500000;
const int MAX_P2 = 200000;
char s[10];
int map[10][10];
int a1_cnt, a2_cnt;
struct Node {
ll val;
int step;
} a1[MAX_P1], a2[MAX_P2];
bool operator<(const Node &a, const Node &b) {
return a.val < b.val || a.val == b.val && a.step < b.step;
}
void dfs1(int x, int y, int step) {
ll sum = 0;
for(int i = 1; i <= 5; i++)
for(int j = 1; j <= 5; j++)
sum = sum * 3 + map[i][j];
a1[++a1_cnt] = (Node){ sum, 8 - step };
if(!step)
return;
x > 1 && y > 2 ? swap(map[x][y], map[x - 1][y - 2]), dfs1(x - 1, y - 2, step - 1), swap(map[x][y], map[x - 1][y - 2]), 0 : 0;
x > 2 && y > 1 ? swap(map[x][y], map[x - 2][y - 1]), dfs1(x - 2, y - 1, step - 1), swap(map[x][y], map[x - 2][y - 1]), 0 : 0;
x > 1 && y < 4 ? swap(map[x][y], map[x - 1][y + 2]), dfs1(x - 1, y + 2, step - 1), swap(map[x][y], map[x - 1][y + 2]), 0 : 0;
x > 2 && y < 5 ? swap(map[x][y], map[x - 2][y + 1]), dfs1(x - 2, y + 1, step - 1), swap(map[x][y], map[x - 2][y + 1]), 0 : 0;
x < 5 && y > 2 ? swap(map[x][y], map[x + 1][y - 2]), dfs1(x + 1, y - 2, step - 1), swap(map[x][y], map[x + 1][y - 2]), 0 : 0;
x < 4 && y > 1 ? swap(map[x][y], map[x + 2][y - 1]), dfs1(x + 2, y - 1, step - 1), swap(map[x][y], map[x + 2][y - 1]), 0 : 0;
x < 5 && y < 4 ? swap(map[x][y], map[x + 1][y + 2]), dfs1(x + 1, y + 2, step - 1), swap(map[x][y], map[x + 1][y + 2]), 0 : 0;
x < 4 && y < 5 ? swap(map[x][y], map[x + 2][y + 1]), dfs1(x + 2, y + 1, step - 1), swap(map[x][y], map[x + 2][y + 1]), 0 : 0;
}
void dfs2(int x, int y, int step) {
ll sum = 0;
for(int i = 1; i <= 5; i++)
for(int j = 1; j <= 5; j++)
sum = sum * 3 + map[i][j];
a2[++a2_cnt] = (Node){ sum, 7 - step };
if(!step)
return;
x > 1 && y > 2 ? swap(map[x][y], map[x - 1][y - 2]), dfs2(x - 1, y - 2, step - 1), swap(map[x][y], map[x - 1][y - 2]), 0 : 0;
x > 2 && y > 1 ? swap(map[x][y], map[x - 2][y - 1]), dfs2(x - 2, y - 1, step - 1), swap(map[x][y], map[x - 2][y - 1]), 0 : 0;
x > 1 && y < 4 ? swap(map[x][y], map[x - 1][y + 2]), dfs2(x - 1, y + 2, step - 1), swap(map[x][y], map[x - 1][y + 2]), 0 : 0;
x > 2 && y < 5 ? swap(map[x][y], map[x - 2][y + 1]), dfs2(x - 2, y + 1, step - 1), swap(map[x][y], map[x - 2][y + 1]), 0 : 0;
x < 5 && y > 2 ? swap(map[x][y], map[x + 1][y - 2]), dfs2(x + 1, y - 2, step - 1), swap(map[x][y], map[x + 1][y - 2]), 0 : 0;
x < 4 && y > 1 ? swap(map[x][y], map[x + 2][y - 1]), dfs2(x + 2, y - 1, step - 1), swap(map[x][y], map[x + 2][y - 1]), 0 : 0;
x < 5 && y < 4 ? swap(map[x][y], map[x + 1][y + 2]), dfs2(x + 1, y + 2, step - 1), swap(map[x][y], map[x + 1][y + 2]), 0 : 0;
x < 4 && y < 5 ? swap(map[x][y], map[x + 2][y + 1]), dfs2(x + 2, y + 1, step - 1), swap(map[x][y], map[x + 2][y + 1]), 0 : 0;
}
int binary_search(ll key) {
int l = 1, r = a2_cnt, ans = -1;
while(l <= r) {
int mid = l + r >> 1;
if(a2[mid].val >= key)
ans = mid, r = mid - 1;
else
l = mid + 1;
}
return ans;
}
int main() {
for(int i = 1; i <= 5; i++)
for(int j = 1; j <= 5; j++) {
if(i ^ j)
map[i][j] = i < j;
if(!(i ^ j))
map[i][j] = i == 3 ? 2 : i < 3;
}
a2_cnt = 0;
dfs2(3, 3, 7);
sort(a2 + 1, a2 + a2_cnt + 1);
int t;
scanf("%d", &t);
while(t--) {
int x, y;
for(int i = 1; i <= 5; i++) {
scanf("%s", s + 1);
for(int j = 1; j <= 5; j++) {
map[i][j] = s[j] == '*' ? 2 : s[j] - 48;
if(map[i][j] == 2)
x = i, y = j;
}
}
a1_cnt = 0;
dfs1(x, y, 8);
int ans = 16;
for(int i = 1; i <= a1_cnt; i++) {
int l = binary_search(a1[i].val);
if(a2[l].val == a1[i].val && a1[i].step + a2[l].step < ans)
ans = a1[i].step + a2[l].step;
}
printf("%d\n", ans == 16 ? -1 : ans);
}
return 0;
}