题目描述
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;
}