• [BZOJ1085] [SCOI2005]骑士精神


    Description

      在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑
    士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空
    位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步
    数完成任务。

    Input

      第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑
    士,*表示空位。两组数据之间没有空行。

    Output

      对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。

    Sample Input

    2
    10110
    01*11
    10111
    01001
    00000
    01011
    110*1
    01110
    01010
    00100

    Sample Output

    7
    -1


    暴力搜索明显会超时,因为步数不多,可以考虑迭代加深搜索。

    但是仍然过不去,需要A*剪枝。

    本题大多数人的估价函数是不在应该在的位置上点的个数。

    但是这个估价函数在只剩下一步就可以成功的时候是不成立的。

    如果最后一步交换空格和一个棋子使得为目标状态,我们的估价函数的值是2,但是实际只需要一步,不满足估价函数的定义。

    所以真正的估价函数是上面得到的答案减1,但是这个估价函数距离真正答案的距离更大,效果没有原本的好,实测估价函数仅少了1,却慢了4倍!!

    玄学的搜索,玄学的剪枝啊!


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    using namespace std;
    #define reg register
    int T;
    char mp[7][7];
    
    bool Flag;
    
    const int tab[7][7] = {
        {0, 0, 0, 0, 0, 0}, 
        {0, 1, 1, 1, 1, 1}, 
        {0, 0, 1, 1, 1, 1}, 
        {0, 0, 0, -1, 1, 1}, 
        {0, 0, 0, 0, 0, 1}, 
        {0, 0, 0, 0, 0, 0}
    };
    const int dx[]={0, -2, -2, 2, 2, 1, -1, 1, -1}, dy[]={0, 1, -1, 1, -1, 2, -2, -2, 2};
    
    int a[7][7];
    int h() {
        int res = 0;
        for (reg int i = 1 ; i <= 5 ; i ++)
            for (reg int j = 1 ; j <= 5 ; j ++)
                res += a[i][j] != tab[i][j];
        return res;
    }
    int ans;
    void IDAstar(int dep, int x, int y)
    {
        if (Flag) return ;
        if (dep == ans) {
            if (!h()) Flag = 1;
            return ;
        }
        for (reg int i = 1 ; i <= 8 ; i ++)
        {
            int tx = x + dx[i], ty = y + dy[i];
            if (tx <= 0 or tx > 5 or ty <= 0 or ty > 5) continue;
            swap(a[x][y], a[tx][ty]);
            if (dep + h() <= ans)
                IDAstar(dep + 1, tx, ty);
            swap(a[x][y], a[tx][ty]);
        }
    }
    
    int main()
    {
        scanf("%d", &T);
        while(T--)
        {
            int xx = 0, yy = 0;
            for (reg int i = 1 ; i <= 5 ; i ++)
            {
                scanf("%s", mp[i] + 1);
                for (reg int j = 1 ; j <= 5 ; j ++)
                {
                    if (mp[i][j] == '*') xx = i, yy = j, a[i][j] = -1;
                    else a[i][j] = mp[i][j] - '0';
                }
            }
            if (!h()) {puts("0");continue;}
            Flag = 0;
            ans = 1;
            for ( ; !Flag and ans <= 16 ; ans++) IDAstar(0, xx, yy);
            if (ans == 17) puts("-1");
            else printf("%d
    ", ans - 1);
        }
        return 0;
    }
  • 相关阅读:
    Redis 6.0 新特性多线程连环13问!
    这些Java8官方挖过的坑,你踩过几个?
    读Hadoop3.2源码,深入了解java调用HDFS的常用操作和HDFS原理
    AI学习笔记:人工智能与机器学习概述
    千亿级互联网平台技术架构及背后那些事
    报告老板,微服务高可用神器已祭出,您花巨资营销的高流量来了没?
    千亿级平台技术架构:为了支撑高并发,我把身份证存到了JS里
    从技术思维角度聊一聊『程序员』摆地摊的正确姿势
    TryCatch包裹的代码异常后,竟然导致了产线事务回滚!
    SpringBoot集成邮件发送
  • 原文地址:https://www.cnblogs.com/BriMon/p/9775709.html
Copyright © 2020-2023  润新知