[高级搜索]骑士精神

题目链接

解题思路

这道题方法很多。

我们首先思考一下,这道题只要大于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 ("\n");
            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\n", 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];这样定义好用一些。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值