P1379 八数码难题 题解
IDA* 练习题
由于题目问最小步数,很好想到可以用迭代式加深搜索,或是广搜,这里用的是深搜。
枚举每次搜索的深度,也就是移动的步数,然后正常深搜,若达到目标解,返回 \(\text{ture}\),然后输出深度即可。
无效性剪枝:减去自己之前来过的方向,也就是如果自己上一步往上走,下一步就不能往下走之类的。
然后就过了……
所以貌似用不着 A* ……
启发式搜索:利用估价函数进行剪枝。
本题估计函数:目标方阵与现在方阵相同的数的个数(不包括 现在方阵的 \(0\))。
若估价函数比剩余步数要大,剪枝即可。
加 A* 前:\(3.5s\)
加 A* 后:\(241ms\)
#include<iostream>
#include<cstdio>
using namespace std;
int a[4][4],b[4][4],f[4][2]={{1,0},{-1,0},{0,1},{0,-1}},vis[4][4]=
{
{0,0,0,0},
{0,1,2,3},
{0,8,0,4},
{0,7,6,5}
};
inline int A()
{
int sum=0;
for(int i=1;i<=3;i++)for(int j=1;j<=3;j++)sum+=((b[i][j]!=0)&(vis[i][j]!=b[i][j]));
return sum;
}
bool dfs(int x,int y,int step,int from)
{
int num=A();
if(num==0)return true;
if(num>step)return false;
for(int i=0;i<4;i++)
{
if((i^1)==from)continue;
int xx=x+f[i][0],yy=y+f[i][1];
if(xx<1||yy<1||xx>3||yy>3)continue;
b[x][y]^=b[xx][yy]^=b[x][y]^=b[xx][yy];
if(dfs(xx,yy,step-1,i))return true;
b[x][y]^=b[xx][yy]^=b[x][y]^=b[xx][yy];
}
return false;
}
int main()
{
int x,y;
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
scanf("%1d",&a[i][j]);
if(a[i][j]==0)x=i,y=j;
}
}
for(int j=1;j<=3;j++)for(int k=1;k<=3;k++)b[j][k]=a[j][k];
for(int i=0;;i++)
{
if(dfs(x,y,i,15))
{
printf("%d",i);
break;
}
}
return 0;
}

浙公网安备 33010602011771号