启发式搜索-A*
估价函数
对于当前状态,我们可以将其与目标状态对比,得到一个预估的代价,即最少(不一定满足题意)的代价,得到这个代价的函数叫做估价函数
对于一个最短路问题来说,我们可以定义一个如下的函数式来表示搜索的过程
[f^*(x)=g^*(x)+h^*(x)
]
其中,f*(x)
为从x到目标节点预估的总代价,g*(x)
表示目前到达x点已经付出的代价,h*(x)
表示预估从x到目标的最小代价,如上题(骑士精神)中,f(x)用迭代加深枚举出来,g(x)为已经走的步数(已知),h*(x)则可表示为目前局面与目标局面的不同点的个数。
上题代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[5][5];
int _std[5][5]= {
{1,1,1,1,1},
{0,1,1,1,1},
{0,0,-1,1,1},
{0,0,0,0,1},
{0,0,0,0,0}
};
int dx[]={0,-2,-2,-1,-1,1,1,2,2}; //重点,剪枝,两边对称并在下面判断防止走回去
int dy[]={0,-1,1,-2,2,-2,2,-1,1};
int ans;
int lim;
int fc()
{
int ret=0;
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
if(a[i][j]!=_std[i][j]) {
ret++;
}
}
}
return ret;
}
void dfs(int x,int y,int step,int f)
{
int diff=fc();
if(diff+step>lim)return;
if(step>=ans)return;
if(diff==0) {
ans=step;
return;
}
for(int i=1; i<=8; i++) {
if(x+dx[i]<0||(x+dx[i]>4)) continue;
if(y+dy[i]<0||(y+dy[i]>4)) continue;
if(i+f!=9) {
swap(a[x+dx[i]][y+dy[i]],a[x][y]);
dfs(x+dx[i],y+dy[i],step+1,i);
swap(a[x+dx[i]][y+dy[i]],a[x][y]);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--) {
int x,y;
ans=20;
int dif=0;
for(int i=0; i<5; i++) {
for(int j=0; j<5; j++) {
char tmp;
cin>>tmp;
if(tmp=='1') {
a[i][j]=1;
}
if(tmp=='0') {
a[i][j]=0;
}
if(tmp=='*') {
a[i][j]=-1;
x=i;
y=j;
}
if(a[i][j]!=_std[i][j])dif++;
}
}
for(int i=dif;i<=16;i++){
lim=i;
dfs(x,y,0,0);
}
printf("%d
",ans==20? -1:ans);
}
return 0;
}
而对于上题的搜索则需要最优性剪枝,通过变化数组的遍历方式防止走回去