1. 程式人生 > >BZOJ 1085 淺談迭代加深式法則及Astar啟發式搜尋路徑誘導

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
*/

嗯,就是這樣