题目链接
解题思路
这道题方法很多。
我们首先思考一下,这道题只要大于15就输出-1了,然后又要让我们求最小值,显然。可以用迭代加深来搞。
我们直接枚举最小的步数即可。
但这样仅仅20分...你想嘛,如果没有任何优化,其实就跟暴力是一样的...在这里,我们引进一个乐观估计函数。
何为乐观估计函数,其实这道题就是在最优情况下达到目标图的最小步数。
就是说一定要小于等于实际步数。
如果当前步数加上乐观估计的步数依旧不行,那么就没必要继续往下面搜索了,很轻松啊。
其实有些人就会有些疑问,因为有些时候,好像自己打搜索也加了这些优化,但是却是全部都爆了。这很显然....你做的不是搜索题目....但是有剪枝优化的思想还是很好的。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n, G[10][10], sx, sy, ans;
int dir[8][2] = {{1, -2}, {2, -1}, {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}};//方向函数
int goal[10][10] = {
{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 check (){//乐观估计函数
int sum = 0;
for (int i = 1; i <= 5; i ++){
for (int j = 1; j <= 5; j ++){
if (goal[i][j] != G[i][j])
sum ++;
}
}
return sum;
}
bool pd (int x, int y){
if (x < 1 || y < 1 || x > 5 || y > 5)
return 0;
return 1;
}
bool iddfs (int x, int y, int depth, int maxdep){//迭代加深
if (depth == maxdep){
if (! check ())
return 1;
return 0;
}
for (int i = 0; i < 8; i ++){
int tox = x + dir[i][0];
int toy = y + dir[i][1];
if (pd (tox, toy)){
swap (G[x][y], G[tox][toy]);
if (check () + depth <= maxdep)
if (iddfs (tox, toy, depth + 1, maxdep))
return 1;
swap (G[x][y], G[tox][toy]);
}
}
return 0;
}
int main (){
scanf ("%d", &n);
while (n --){
ans = -1;
for (int i = 1; i <= 5; i ++){
scanf ("
");
for (int j = 1; j <= 5; j ++){
char c;
scanf ("%c", &c);
if (c == '*') G[i][j] = 2, sx = i, sy = j;
else G[i][j] = c - 48;
}
}
for (int i = 0; i <= 15; i ++){
if (iddfs (sx, sy, 0, i)){
ans = i;
break;
}
}
printf ("%d
", ans);
}
return 0;
}
这种方法固然可行,但我们还可用另一种高级搜索的方法。
题目给出了初始图和目标图,我们知道起点与终点,于是我们就可以用双向BFS,但问题来了,搜索的话我们肯定有些东西是重复进行了搜索,如何避免呢?
图是一个矩阵,我们不好进行标记,这里,我们就要考虑用到哈希。看原图,除去星号就是由01组成的,可以说是二进制编码。因此呢,我们就可以用二进制来表示。
但是会有一个问题,那就是不同的图依旧有同样的值。这里我们就需要考虑到星号的坐标,这样我们就可以保证唯一了。
我们判断一下范围,发现数值刚好卡在int那里,肯定可以算出。于是就可以用map来弄
但我们是用的2进制编码,这样其实相对来讲很难表示,如果用二维数组的话,则更难弄出来。
于是呢,我选择暴力。
我直接用3进制,这样就不会有重复了。
LL gethash(node a) {
LL k = 1, ans = 0;
for (int i = 1; i <= 5; i ++) {
for (int j = 1; j <= 5; j ++){
ans += k * a.word[i][j];
k *= 3;
}
}
return ans;
}
没啥好讲的,毕竟是搜索,相信大家都会
map<LL, edge> vis[2];这样定义好用一些。