BZOJ 1085 淺談迭代加深式法則及Astar啟發式搜尋路徑誘導
世界真的很大
Astar的第二題,在Astar剪枝的同時使用了迭代加深的搜尋方式
將談談迭代加深搜尋和Astar的估價函式在剪枝方面的應用
聽起來可能感覺不可做其實就是暴力+優化而已
搜尋題寫起來還是很舒服的只是調起來就不是那麼親民了
好在調的還算比較快
看題先:
description:
在一個5×5的棋盤上有12個白色的騎士和12個黑色的騎士, 且有一個空位。在任何時候一個騎士都能按照騎
士的走法(它可以走到和它橫座標相差為1,縱座標相差為2或者橫座標相差為2,縱座標相差為1的格子)移動到空
位上。 給定一個初始的棋盤,怎樣才能經過移動變成如下目標棋盤: 為了體現出騎士精神,他們必須以最少的步
數完成任務。
input:
第一行有一個正整數T(T<=10),表示一共有N組資料。接下來有T個5×5的矩陣,0表示白色騎士,1表示黑色騎
士,*表示空位。兩組資料之間沒有空行。
output:
對於每組資料都輸出一行。如果能在15步以內(包括15步)到達目標狀態,則輸出步數,否則輸出-1。
考慮直接爆搜
但是爆搜有一個問題,就是考慮在搜尋樹上,如果當前搜尋路徑上沒有答案,那麼其實這條搜尋路徑就是不必要的
但是我們事先並不知道有沒有答案,DFS是不撞南牆不回頭的
所以會直線搜尋下去,很可能會爆棧然後卡死
迭代加深搜尋適用的,就是這種情況
我們人為地限制搜尋樹的高度,然後列舉這個高度多次搜尋
在搜尋樹擴散很快,轉移很多的時候這種方法尤其好用
即我們從小到大列舉步數,然後搜尋在這個步數內能不能搜尋到答案
這算是一般搜尋的一個優化吧
然後這樣可能時間上還是有一點卡或者說還是會超時
需要進一步優化搜尋
Astar演算法,就是搜尋的一個強有力的剪枝,剪枝力度及正確性取決與估價函式的精度的一個演算法
如果要用Astar來剪枝的話,估價函式,即 f = g + h 裡面的h怎麼辦呢
h的含義就是指我估計從當前局面到目標局面所走的步數
那麼g就是指我已經走的步數
如何估計我還要走多少步呢?
這個的確是比較難以處理,具體值實在是難以把握,但如果因為估計的失誤導致搜尋漏掉正解的話,就得不償失了
所以我們寧可估價函式的力度小一點,也不要讓他出錯
那就估計一個相對準確的“下界”,如何?
即至少要走多少步
這個我們就通過當前局面和目標局面有多少個不同之處來判斷了
因為如過當前局面與目標局面有x個位置不同,至少再走x-1步對吧
這是由於空的位置只有
用這個來充當估價函式來估計準確的下界就沒問題了
如果加上這個這個函式之後大於了迭代值就不繼續搜尋了
完整程式碼:
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
int T;
int mp[6][6],sd[6][6];
int fx[8]={1,1,2,2,-1,-1,-2,-2},fy[8]={-2,2,-1,1,-2,2,-1,1};
char ss[10];
void init()
{
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
if(j>=i && i<=2) sd[i][j]=1;
else if(j>i && i>=3) sd[i][j]=1;
else if(i==3&&j==3) sd[i][j]=2;
}
bool check()
{
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
if(mp[i][j]!=sd[i][j]) return false ;
return true ;
}
int estimate()
{
int rt=0;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
rt+=(mp[i][j]!=sd[i][j]);
return rt-1;
}
bool dfs(int x0,int y0,int maxn,int state)
{
if(state==maxn) return check();
for(int i=0;i<8;i++)
{
int x1=x0+fx[i],y1=y0+fy[i];
if(x1<1 || x1>5 || y1<1 || y1>5) continue ;
swap(mp[x0][y0],mp[x1][y1]);
if(estimate()+state<=maxn)
if(dfs(x1,y1,maxn,state+1)) return 1;
swap(mp[x0][y0],mp[x1][y1]);
}
return 0;
}
int main()
{
init();
scanf("%d",&T);
while(T--)
{
int flag=1,Sx,Sy;
for(int i=1;i<=5;i++)
{
scanf("%s",ss+1);
for(int j=1;j<=5;j++)
if(ss[j]=='1') mp[i][j]=1;
else if(ss[j]=='0') mp[i][j]=0;
else mp[i][j]=2,Sx=i,Sy=j;
}
for(int i=0;i<=15;i++)
if(flag && dfs(Sx,Sy,i,0))
flag=0,printf("%d\n",i);
if(flag) printf("-1\n");
}
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/
嗯,就是這樣