IDA*知识点讲解&&[SCOI2005]骑士精神

 题目描述

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

输入格式

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

输出格式

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

输入输出样例

输入样例1:                                                                        输出样例1:            

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

说明

【样例说明】

样例中第二个数据的初始情况对应图:

【耗时限制】1000ms 【内存限制】128MB


哎,这一题楼主写了大半个小时,样例就不过,就无语

检查了好久才发现是有一个剪枝写错了

这是一个标标准准的IDA*

首先,我们先科普一下什么是IDA*

A*算法的本质是带估价函数的优先队列BFS。其需要维护一个优先队列(二叉堆)来存储状态及其估价,耗费空间较大,时间也较大(每次操作需要log2(n))的时间。

考虑将估价函数和DFS相结合,DFS有个缺点,就是一旦估价出现失误,容易向下递归深入一个不能产生最优解的分支,浪费许多时间。

为了规避DFS的缺点,考虑将估价函数和迭代加深的DFS算法相结合。该算法限定一个深度,在不超过该深度的前提下执行DFS,如果找不到解就扩大深度限制,重新进行搜索。

设计一个估价函数,估算从每个状态到目标状态需要的步数。和A*算法一样,估价函数需要确保:“估计值 深度限制,则立即从当前分支回溯。

那我们了解完了IDA*是什么之后,我们就来看一下这一题

裸的IDA*啊

深度已经给了上限了,最多15层,再加一些剪枝优化,绝对不可能超时

算了吧,不说那么多了

代码里有注释,自己瞅吧

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
const int N=10; 
int dep;
const int dir[8][2]={{1,2},{2,1},{2,-1},{1,-2},{-1,2},{-2,1},{-2,-1},{-1,-2}};
//必须按这种顺序来,首尾配对,正好每一对都互逆
const int mb[N][N]={{},
					{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 g[N][N],ans;
inline int count(){
    int cnt=0;
    for(int i=1;i<=5;i++) 
        for(int j=1;j<=5;j++) 
			if(g[i][j]!=mb[i][j]) cnt++;
    return cnt;
}
inline bool check(int x,int y){ 
	return x>=1&&x<=5&&y>=1&&y<=5;
}
bool IDAstar(int x,int y,int dq,int last){//dq:当前,表示当前深度 
	int m=count();
    if(!m) return true;
    if(dq+m>dep+1) return false;
    for(int i=0;i<8;i++){
		if(i+last==7) continue;
		//last是上一个处理的,防止上一个和这一个的操作正好相反,抵消了 
        int tx=x+dir[i][0],ty=y+dir[i][1];
        if(check(tx,ty)){//判断位置在网格内 
        	swap(g[x][y],g[tx][ty]);//move移动 
            if(IDAstar(tx,ty,dq+1,i)) return true;
            swap(g[x][y],g[tx][ty]);//没有return true说明不行,再恢复原来状态 
       	}
    }
	return false;
}
int main(){
    int t,sx,sy; 
	scanf("%d",&t);
    while(t--){
        for(int i=1;i<=5;i++){
            for(int j=1;j<=5;j++){
                char in; cin>>in;
                if(in=='*') g[i][j]=2,sx=i,sy=j;
                else g[i][j]=in-'0';
            }
        }
        for(dep=0;dep<=15;dep++){
            if(IDAstar(sx,sy,0,-1)){ 
            	break;	
			}
        }
        if(dep>15) dep=-1;
		printf("%d\n",dep); 
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值