關於啟發式搜尋
阿新 • • 發佈:2022-05-13
一.定義:
顧名思義,啟發式搜尋肯定不是普通的搜尋,而是在普通的搜尋上做了一些啟發,進行了一些優化。
一般啟發式搜尋分為兩種型別,一種是優化廣度優先搜尋的 \(A\) * 演算法(),一種是優化深度優先搜尋的 \(IDA\) * 演算法
二.基本函式:
1.距離函式 \(g(x)\):
用來計算當前點到起點的距離,也就是已消耗的代價。
2.估價函式 \(h(x)\):
用來估計最優情況下,從當前點到終點所要走的距離,也就是所要消耗的代價。
3.計算函式 \(f(x)\):
計算距離函式和估價函式的和值。
三.圖例分析:
\(A\)*演算法的操作步驟如圖所示,這樣可以大大縮減爆搜的時間複雜度
但是有一些極端的特殊情況需要注意:
四.注意事項:
這裡一定要注意估價一定要小於等於實際值,因為若估價比實際大,在某些情況下,可能實際值更大的反而被取出來就會導致答案錯誤。
典型例題
例一 一本通1251 仙島求藥
這題雖然用爆搜隨便就能做出來,資料範圍很小,但用來練習啟發式搜尋還是可以的。
下面展示一下啟發式搜尋用結構體形式實現的程式碼。
Code
#include<bits/stdc++.h> using namespace std; int n,m,ex,ey; char s[25][25]; bool vis[25][25]; struct Node { int x; int y; int g; int h; int f; bool operator<(const Node b)const { return f>b.f; } }start; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; inline int bfs() { memset(vis,false,sizeof(vis)); priority_queue<Node>q; start.g=0; start.h=abs(start.x-ex)+abs(start.y-ey); start.f=start.g+start.h; q.push(start); vis[start.x][start.y]=true; while(!q.empty()) { Node now=q.top(); q.pop(); for(register int i=0;i<=3;i++) { int nx=now.x+dx[i]; int ny=now.y+dy[i]; if(nx<1||ny<1||nx>m||ny>n||s[nx][ny]=='#'||vis[nx][ny]==true) continue; if(s[nx][ny]=='*') return now.g+1; Node nxt; nxt.x=nx; nxt.y=ny; nxt.g=now.g+1; nxt.h=abs(nxt.x-ex)+abs(nxt.y-ey); nxt.f=nxt.g+nxt.h; q.push(nxt); vis[nxt.x][nxt.y]=true; } } return -1; } int main() { while(cin>>m>>n) { if(m==0&&n==0) return 0; for(register int i=1;i<=m;i++) { for(register int j=1;j<=n;j++) { cin>>s[i][j]; if(s[i][j]=='@') start.x=i,start.y=j; if(s[i][j]=='*') ex=i,ey=j; } } printf("%d\n",bfs()); } return 0; }
這裡有可以優化的點,看到資料範圍 \(n,m \le 20\) 就可以想到用一個頂多四位的數來表示它的狀態,隨即可以將標記陣列 \(vis_i\) 優化為一維。
Code
#include<bits/stdc++.h> using namespace std; int n,m,e; char s[25][25]; bool vis[2025]; struct Node { int state; int g; int h; int f; bool operator<(const Node b)const { return f>b.f; } }start; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; inline int bfs() { memset(vis,false,sizeof(vis)); priority_queue<Node>q; start.g=0; start.h=abs(start.state/100-e/100)+abs(start.state%100-e%100); start.f=start.g+start.h; q.push(start); vis[start.state]=true; while(!q.empty()) { Node now=q.top(); q.pop(); for(register int i=0;i<=3;i++) { int nx=now.state/100+dx[i]; int ny=now.state%100+dy[i]; if(nx<1||ny<1||nx>m||ny>n||s[nx][ny]=='#'||vis[nx*100+ny]==true) continue; if((nx*100+ny)==e) return now.g+1; Node nxt; nxt.state=nx*100+ny; nxt.g=now.g+1; nxt.h=abs(nx-e/100)+abs(ny-e%100); nxt.f=nxt.g+nxt.h; q.push(nxt); vis[nxt.state]=true; } } return -1; } int main() { while(cin>>m>>n) { if(m==0&&n==0) return 0; for(register int i=1;i<=m;i++) { for(register int j=1;j<=n;j++) { cin>>s[i][j]; if(s[i][j]=='@') start.state=i*100+j; if(s[i][j]=='*') e=i*100+j; } } printf("%d\n",bfs()); } return 0; }