洛谷 P1379 八数码难题
Description
Solution
似乎各种做法都可以过,我写的 \(IDA^*\)。
很明显,乐观估价函数即为当前棋盘与目标棋盘上不同的数字个数。
所以直接枚举深搜层数,然后搜索即可。
\(IDA^*\) 的主要难度就在乐观估价函数上,这个弄明白之后,就很简单了。
然后这个写法上面还有一点问题,总之背过板子就好。
另外,还要加一个剪枝:不能走向上一个格子。
简单来说就是不能来回走。这个把方向数组构造一下,然后判断一下即可,见代码。
其他的就没什么了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
int a[5][5];
int b[4][4] = {
0, 0, 0, 0,
0, 1, 2, 3,
0, 8, 0, 4,
0, 7, 6, 5
};
int tmp, ans, flag;
int dx[4] = {-1, 0, 0, 1};
int dy[4] = {0, -1, 1, 0};
//上左右下
inline int check(){
int res = 0;
for(int i = 1; i <= 3; i++)
for(int j = 1; j <= 3; j++)
res += (a[i][j] != b[i][j]);
return res;
}
inline void dfs(int x, int y, int step, int pre){
if(step == tmp){
if(!check()) flag = 1;
return;
}
if(flag) return;
for(int i = 0; i < 4; i++){
int mx = x + dx[i];
int my = y + dy[i];
if(mx < 1 || mx > 3 || my < 1 || my > 3 || i + pre == 3) continue;
swap(a[x][y], a[mx][my]);
if(!flag && check() + step <= tmp) dfs(mx, my, step + 1, i);
swap(a[x][y], a[mx][my]);
}
}
int main(){
int x, y;
for(int i = 1; i <= 3; i++)
for(int j = 1; j <= 3; j++){
char c = getchar();
if(c == '0') x = i, y = j;
a[i][j] = c - '0';
}
if(!check()){
puts("0");
return 0;
}
for(tmp = 1; ; tmp++){
dfs(x, y, 0, -1);
if(flag){
printf("%d\n", tmp);
return 0;
}
}
return 0;
}