啟發式搜索-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\n",ans==20? -1:ans);
}
return 0;
}
而對於上題的搜索則需要最優性剪枝,通過變化數組的遍歷方式防止走回去