【题解】P2324[SCOI2005] 骑士精神

Description

在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。

在任何时候一个骑士都能按照骑
士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空
位上。

给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步
数完成任务。

目标状态:

Sample Input

2

10110

01*11

10111

01001

00000

01011

110*1

01110

01010

00100

Sample Output

7

-1

Hint

\(T \leqslant 10\)

Solution

最暴力:直接暴力动空格,复杂度 \(O(8^{step})\),有点 \(wei\)。。。

首先我们发现这题其实这个数据范围好像爆搜不大 \(wei\) ,再观察题面,发现这题说超过 \(15\) 步输出 \(-1\),emmm好像可以用迭代加深。

但是我们都知道迭代加深其实和宽搜差不了多少。。。还是过不了。

那咋的办。考虑对于所有爆搜的题大部分可以依靠 \(A*\) 获得不错的效率,当然不排除,\(A*\) 估价写 \(wei\) 丢失最优解。

关于估价函数的一些小细节:

  • 估价函数最好小于等于实际的函数值,比如k短路中我们以到终点的最短路作为估价函数。

  • 估价函数的构造肯定是和题目的要求答案有密不可分的关系。

举几个估价函数的小栗子:

  • 迷宫: 到终点的曼哈顿距离
  • K短路:到终点的最短路
  • 求最小步数归位:与终点的状态差距(距离)

由于博主太 \(wei\) 了,没得办法,就会这么点东西,再去刷刷YBT找找感觉。

但是,这样貌似复杂度还是有点高,至少我是过不了,神他喵忘判走过去又走回来的情况了,T飞了。。。

Code

#include<bits/stdc++.h>
using namespace std;
#define R register

int T;
bool flag=false;
const int N=7;
const int dx[]={2,1,-1,-2,-2,-1,1,2};
const int dy[]={1,2,2,1,-1,-2,-2,-1};
const int goal[N][N]={
    {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 a[N][N];
char s[N][N];

inline int h(){
    int ret=0;
    for(int i=1;i<=5;++i) for(int j=1;j<=5;++j)
        ret+=(a[i][j]!=goal[i][j]);
    return ret;
}

inline bool check(){
    for(int i=1;i<=5;++i) for(int j=1;j<=5;++j)
        if(a[i][j]!=goal[i][j]) return true;
    return false;
}

inline void A_star(int deep,int dep,int cx,int cy,int prex,int prey){
    if(dep==deep){
        if(!check()) flag=true;
        return;
    }
    for(int i=0;i<8;++i){
        int x=cx+dx[i],y=cy+dy[i];
        if(x<1 || x>5 || y<1 || y>5 || (x==prex&& y==prey)) continue;
        swap(a[cx][cy],a[x][y]);
        if(dep+h()<=15)
            A_star(deep,dep+1,x,y,cx,cy);
        swap(a[cx][cy],a[x][y]);
    }
}

int main(){
    scanf("%d",&T);
    while(T--){
        int sx=0,sy=0;
        flag=false;
        for(R int i=1;i<=5;++i) scanf("%s",s[i]+1);
        for(R int i=1;i<=5;++i) for(int j=1;j<=5;++j){
            if(s[i][j]=='*') a[i][j]=2,sx=i,sy=j;
            else a[i][j]=s[i][j]-'0';
        }
        for(int i=1;i<=15;++i){
            A_star(i,0,sx,sy,0,0);
            if(flag==true){
                printf("%d\n",i);
                break;
            }
        }
        if(flag==false) puts("-1");
    }
    return 0;
}
posted @ 2019-05-14 22:03  章鱼那个哥  阅读(229)  评论(0编辑  收藏  举报