1. 程式人生 > 其它 >關於啟發式搜尋

關於啟發式搜尋

一.定義:

顧名思義,啟發式搜尋肯定不是普通的搜尋,而是在普通的搜尋上做了一些啟發,進行了一些優化。
一般啟發式搜尋分為兩種型別,一種是優化廣度優先搜尋的 \(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;
}

例二