[模板A*][SCOI2005]骑士精神(A*,IDA*)

[模板A*][SCOI2005]骑士精神(A*,IDA*)
输入格式
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。

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

这题是一道比较好的\(A*\)的模板题,\(A*\)对dfs的优化一般叫\(IDA*\)。

首先,\(A*\)有一个定义式叫做:

\(f(n)=g(n)+h(n)\)

\(f(n)\)即为一点的估价函数,\(g(n)\)是这一点实际所用的步数(价值),\(h(n)\)是对未来的所需步数(代价)的完美预测(接近完美)。

通过这个定义式,只要有h(n),每次都可以算出一个点的估价,\(A*\)算法就是通过限制估价,使得在搜索的时候不要在无意义的道路上浪费时间。即,每次限制每个点的估价\(maxdep\),一旦估价超过,就停止搜索。

根据定义式,\(h(n)\)一定要\(<=\)实际的所需步数。

[模板A*][SCOI2005]骑士精神(A*,IDA*)
像这张图,如果\(h(A)\)估大了的话,\(f(A)\)也会相应变大,这样\(f(A)\)有可能会被maxdep给去掉,从而找不到正确答案。

所以,为了保证答案的正确性,\(h(A)\)一定要在\(<=\)实际的所需步数的前提下尽量的大,也就是尽量估得准。

那回到这题,题目要求在15步以内完成才输出步数,否则-1,所以可以将maxdep从0到15枚举,一旦成功找到,那就是答案(最少步数)。

而最优的就是每一次都将不在相应位置上的棋子移到相应的位置上,所以\(h(A)\)可以是不匹配的棋子数,因为每次最多还原一个,所以\(h(A)\)一定是\(<=\)实际的所需步数,正确性得到保证。

\(h(A)\):

int value()
{
    int ans=0;
    for(int i=0;i<5;i++)
    {
        for(int j=0;j<5;j++)
        {
            if(standard[i][j]!=tu[i][j])
            {
                ans++;
            }
        }
    }
    return ans;
}

然后就是时间的剪枝,题目要的是最少步数,所以肯定不能做回头路,还有就是没有找到完成的路径,满足这两点,加上maxdep的限制,才能继续往下搜。

其他就是一个暴力搜索了,没什么好讲的:

#include<bits/stdc++.h>
using namespace std;
int standard[5][5]={{1,1,1,1,1},{0,1,1,1,1},{0,0,-1,1,1},{0,0,0,0,1},{0,0,0,0,0}},tu[5][5],f[8][2]={{-2,-1},{-2,1},{1,2},{1,-2},{-1,2},{-1,-2},{2,-1},{2,1}},is,t,xx,yy;
char ch;
int value()//估价函数
{
    int ans=0;
    for(int i=0;i<5;i++)
    {
        for(int j=0;j<5;j++)
        {
            if(standard[i][j]!=tu[i][j])
            {
                ans++;
            }
        }
    }
    return ans;
}
void dfs(int dep,int x,int y,int maxdep,int lastway)//直接搜
{
    if(dep==maxdep)
    {
        if(!value())
        {
            is=1;
        }
        return;
    }
    for(int i=0;i<8;i++)
    {
        int xx=x+f[i][0];
        int yy=y+f[i][1];
        if(xx<0||xx>4||yy<0||yy>4||7-i==lastway)//不走出格,不走回头路
        {
            continue;
        }
        swap(tu[x][y],tu[xx][yy]);
        if(dep+value()<=maxdep&&!is)//估价函数的限制
        {
            dfs(dep+1,xx,yy,maxdep,i);
        }
        swap(tu[x][y],tu[xx][yy]);
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        is=0;
        for(int i=0;i<5;i++)
        {
            for(int j=0;j<5;j++)
            {
                cin>>ch;
                if(ch=='*')
                {
                    tu[i][j]=-1;
                    xx=i;
                    yy=j;
                }else{
                    tu[i][j]=ch-'0';
                }
            }
        }
        if(!value())
        {
            puts("0");
            return 0;
        }
        for(int i=1;i<=15;i++)//A*
        {
            dfs(0,xx,yy,i,9);
            if(is)
            {
                printf("%d\n",i);
                break;
            }
        }
        if(!is)//没有
        {
            puts("-1");
        }
    }
    return 0;
}
上一篇:2019 计蒜之道 初赛 第五场 浪潮集团的“超级大树”


下一篇:linux(二):用户,CPU、内存、磁盘、网络