[SCOI2005] 骑士精神 题解
题目描述
解法
采用 IDA* 算法。不移动骑士而移动空格。每次限制深度,然后对每个遍历到的点进行一次估价,估价函数的值即为当前状态和终点的差异数。
如果估计的加上已经确认的层数比限制搜索的还要多,就直接放弃这个了。
\[\begin{array}{ll}
1 & \textbf{IDA* (point p, w, k) :}\\
2 & \qquad w \leftarrow f(s).\\
3 & \qquad \textbf{if } f(s) = 0 :\\
4 & \qquad \qquad ans \leftarrow g.\\
5 & \qquad \qquad \textbf{Return.}\\
6 & \qquad \textbf{if } ans \text{ have a value } \textbf{or } (w + g)\ge k :\\
7 & \qquad \qquad \textbf{Return.}\\
8 & \qquad \textbf{for} \text{ every legal position of }(x, y):\\
9 & \qquad \qquad \text{swap}(p, (x,y)).\\
10 & \qquad \qquad \text{IDA*}((x,y),w+1,k).\\
11 & \qquad \qquad \text{swap}(p, (x,y)).\\
\end{array}
\]
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int tg[6][6] = {
{0, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 1, 1},
{0, 0, 1, 1, 1, 1},
{0, 0, 0, 2, 1, 1},
{0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0}
};
int g[6][6];
int f() {
int cnt = 0;
for(int i = 1; i <= 5; i ++)
for(int j = 1; j <= 5; j ++)
if(g[i][j] != tg[i][j])
cnt ++;
return cnt;
}
inline int safe(int x, int y){
if(x < 1 || x > 5 || y < 1 || y > 5) return 0;
return 1;
}
int dx[9] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[9] = {-2, 2, 2, -2, 1, -1, -1, 1};
int ans;
void dfs(int k, int x, int y, int w) {
int val = f();
if(!val) {
ans = w;
return;
}
if(w + val > k || ans || w == k) return;
for(int i = 0; i < 8; i ++) {
int X = x + dx[i];
int Y = y + dy[i];
if(!safe(X, Y)) continue;
swap(g[x][y], g[X][Y]);
dfs(k, X, Y, w + 1);
swap(g[x][y], g[X][Y]);
}
}
void solve() {
int x = 0, y = 0;
ans = 0;
for(int i = 1; i <= 5; i ++)
for(int j = 1; j <= 5; j ++) {
char ch;
cin >> ch;
if(ch == '*') x = i, y = j, g[i][j] = 2;
else g[i][j] = ch - '0';
}
if(!f()) {
printf("0\n");
return;
}
for(int k = 1; k <= 16; k ++) {
dfs(k, x, y, 0);
if(ans) {
printf("%d\n", ans);
return;
}
}
printf("-1\n");
}
int main() {
int t;
cin >> t;
while(t --) solve();
}