演算法初探 啟發式搜尋

2022-05-25 11:42:14 字數 4166 閱讀 5258

2020.07.21-11:40

2020.08.30-16:55

[a problem]如果讓你在這麼乙個方格圖中尋找最短路徑,你會怎麼做?

student-a:我會廣度優先演算法!

student-b[最優]:我會貪心走過去!

上面是最簡單的狀況,如果有障礙物呢?

注:綠色格仔不可通過

student-a:我會廣度優先演算法與深度優先演算法!

student-b:我。。

看起來此問題得到了解決,但是我們可以很快想到:樸素的搜尋演算法最壞情況下竟需要遍歷整個圖!!

那麼我們此時需要剪枝,那麼如何剪呢?

最容易想到的就是在某一步發現不管怎麼樣,都不可能達到目標情況或不是最優解,此時直接回溯,效率提高不少

用乙個式子來表示就是:

\(s+h(s)>dep\)

\(s\)就是當前的步數,\(dep\)就是目標

那麼其中的\(h(s)\)就是對當前的乙個估計,稱為估價函式

當前步數+估計》目標,你還會走下去嗎?

當然不會,所以直接回溯

容易發現,估價函式越準確,\(s\)越小,程式越快;估計函式越不准,\(s\)越大,程式越慢

在尋找最短路的問題中,\(h(s)\)就是代表當前到終點的距離

在不同的問題中,\(h(s)\)也有不同的含義

這裡的\(h(s)\)就是沒有在正確位置上的數的個數

首先計算\(dep\),即最少幾步即可到達目標狀況

隨著廣度的放寬,慢慢進行a*搜尋尋找答案

函式中

if(!dis) return 1;

if(s+dis>stdep) return 0;

就是a*的核心

#include#include#define r register

int goalx[9]=,movx[4]=,zx;

int goaly[9]=,movy[4]=,zy;

int stdep;

std::string begin;

inline int abs(int a)

inline int getrow(int a)

inline int getcolumn(int a)

inline int getoriginal(int x,int y)

inline int getdist(std::string a)

std::swap(begin[past],begin[now]);

if(a_star(s+1,past))

return 1;

std::swap(begin[past],begin[now]);

zx-=movx[i],zy-=movy[i];

} return 0;

}signed main()

std::cout同上,這裡的\(h(s)\)是沒有在正確位置上的棋子的個數

#include#include#define r register

using std::string;

string goal[5]=,in[5];

int mx[8]=,sx;

int my[8]=,sy;

int t,dep;

inline int getdist(string a[5])

if(a[i][o]!=goal[i][o]) dist+=1;

} return dist;

}inline bool a_star(int s,int prex,int prey)

std::swap(in[sx3][sy3],in[sx2][sy2]);

if(a_star(s+1,sx3,sy3)) return 1;

std::swap(in[sx3][sy3],in[sx2][sy2]);

sx2-=mx[i],sy2-=my[i];

} return 0;

}signed main()

if(dep==16) printf("-1\n");

else printf("%d\n",dep);

}}

這裡的\(h(s)\)是八宮格內還缺幾個數就滿足題意

讀入比較噁心,要小心寫**

我這篇好像是luogu最優解

【**選注】

char map[8]=;
考慮到字典序的問題,我們列舉的時候1-8,最後來個對應

至於為啥不是i+'a'這種型別,為了保險(懶

int shrc[8]=,dep;

int shru[8]=,ans;

1-8所對應的狀態,為了好處理所以打亂順序,這相當於對應陣列

inline int getsituation()
獲得情況,看看最少還有幾個數沒有回到位置上

inline void change(char a[8],int rc,bool rule)
改動某一行rule取值意義

rc取值意義:

if(!st)
存在不需要搜尋或搜尋完畢的情況,此時記錄,退出

if(shrc[i]==prc&&shru[i]!=pru) continue;
防止出現兩次移動相當於沒移的情況

change(f[shrc[i]],shrc[i],!shru[i]);
相反方向回溯

#includeusing std::cin;

using std::cout;

char f[5][8],lu[100],map[8]=;

int shrc[8]=,dep;

int shru[8]=,ans;

inline int tmax(int a,int b,int c)

inline int getsituation();

a[f[1][3]-'0']+=1;a[f[1][4]-'0']+=1;a[f[1][5]-'0']+=1;

a[f[2][3]-'0']+=1;a[f[2][4]-'0']+=1;a[f[2][5]-'0']+=1;

a[f[3][4]-'0']+=1;a[f[4][4]-'0']+=1;

return 8-tmax(a[1],a[2],a[3]);

}inline void change(char a[8],int rc,bool rule)

else

switch(rc)

}inline bool a_star(int s,int prc,int pru)

if(s+st>dep) return 0;

for(int i=0;i<8;i++)

return 0;

}signed main(){

while(1){

cin>>f[1][1];if(f[1][1]=='0') break;

cin>>f[2][1]>>f[1][2]>>f[2][2];

for(int i=1;i<8;i++) cin>>f[3][i];

f[1][3]=f[3][3],f[2][3]=f[3][5];

cin>>f[1][4]>>f[2][4];

for(int i=1;i<8;i++) cin>>f[4][i];

f[1][5]=f[4][3],f[2][5]=f[4][5];

cin>>f[1][6]>>f[2][6]>>f[1][7]>>f[2][7];

dep=getsituation();ans=f[1][3]-'0';

while(!a_star(0,-1,-1)) dep+=1;

if(!dep) cout<

else for(int i=0;i容易發現,a*與ida*就是在原搜尋的基礎上加上幾行優化的東西,所以啟發式搜尋並沒有那麼難

A 演算法(啟發式搜尋)

a 演算法,a a star 演算法是一種靜態路網中求解最短路徑最有效的直接搜尋方法,也是解決許多搜尋問題的有效演算法。演算法中的距離估算值與實際值越接近,最終搜尋速度越快。別稱 啟發式搜尋 表示式 f n g n h n f n g n h n f n g n h n 公式表示為 f n g n ...

啟發式搜尋

啟發式搜尋 heuristically search 又稱為有資訊搜尋 informed search 它是利用問題擁有的啟發資訊來引導搜尋,達到減少搜尋範圍 降低問題複雜度的目的,這種利用啟發資訊的搜尋過程稱為啟發式搜尋。例題 八數碼問題 運用優先佇列,根據目前已經確定的位置算出目前的價值,並匯入...

啟發式搜尋

啟發式搜尋 啟發式搜尋就是在狀態空間中的搜尋對每乙個搜尋的位置進行評估,得到最好的位置,再從這個位置進行搜尋直到目標。這樣可以省略大量無謂的搜尋路徑,提高了效率。在啟發式搜尋中,對位置的估價是十分重要的。採用了不同的估價可以有不同的效果。在啟發式搜尋中,我們每次找到當前 最有希望是最短路徑 的狀態進...