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;
}
posted @ 2023-02-24 13:33  Gmt丶Fu9ture  阅读(34)  评论(0)    收藏  举报