我們在搜尋的時候往往會發現一些資料會導致我們的普通的深搜與廣搜都無法通過,那這個時候我們就需要讓起點與終點建立一些聯絡,今天我們講述的啟發式搜尋就是在廣度優先搜尋的基礎上加了這樣乙個優化,叫做估價函式。
對於乙個狀態,在我們知道終點狀態的時候,我們可以設計乙個估價函式使我們對這個狀態距離終點的距離有個簡單的了解,並且我們以後就優先取出估價值+目前的步數最小的那個狀態進行擴充套件。
估價函式的實現因題而異,乙個好的估價函式會讓演算法變得很優秀。但是要注意的一點是,估價函式都要是乙個比實際情況更優的估值,也就是說我們的估價值要始終<
=<=
<
=實際步數。
因為我們每次都拿出步數+估價值最優的狀態進行擴充套件,所以我們要把佇列變成,優先佇列。這個實現有點像堆優化後的迪傑斯特拉演算法。
1.將起點初始化之後放入優先佇列。
2.在找到答案且優先隊列為空之前拿出乙個堆頂元素,判斷是否為答案。
3.如果是直接結束迴圈,輸出答案。
4.如果不是就先標記然後向外擴充套件,遇到乙個沒出過堆的元素就將其估價然後放入堆(注意是沒有出過堆,因為乙個狀態可以入隊很多次)
題目鏈結
對於八數碼問題,我們會發現如果我們強行記錄每乙個狀態的話就要開乙個109
10^9
109的陣列,這樣顯然會超記憶體,所以我們這裡要介紹一種叫做康托展開的方式。
康托展開,就是求乙個排列在其全排列中的字典序排名。
其公式是:
x =∑
i=n1
a∗(i
−1)!
x=\sum_^a*(i-1)!
x=i=n∑
1a∗
(i−1
)!下標從左到右降序排列,其中a表示該位右邊有幾個數字比這位數字大。
康托展開**實現:
struct tree
}int
lowbit
(int x)
void
modify
(int pos,
int x)
}int
query
(int pos)
return ans;
}}t;
int jc[10]
;void
work()
return;}
intcantor
(int
*in)
return ans;
}
最後的ac**:
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
using
namespace std;
string str;
int n=9;
int use[10]
;struct tree
}int
lowbit
(int x)
void
modify
(int pos,
int x)
}int
query
(int pos)
return ans;
}}t;
int jc[10]
;void
work()
return;}
intcantor
(int
*in)
return ans;
}int first_cantor;
//起始狀態
stack<
int>ans;
//記錄答案的棧,便於逆序輸出
struct nodep[
400000];
int x[10]
=;int y[10]
=;int xx[4]
=;//廣搜狀態所用
int yy[4]
=;int judgex[4]
=;//71 72都是座標改變
int judgey[4]
=;bool vis[
400000];
intguess
(node d)
}//cout}bool
operator
<
(node a,node b)
priority_queueq;
bool flag=0;
//是否找到答案
int dist[
400000];
//儲存每個康托值所對應的最優答案
void
bfs(
)return;}
if(dist[k.cantor]
!=k.dist)
return
;int id_x=0;
//9所在的地方
int x1=
0,y1=0;
//對應的座標
node b;
//待擴充套件的新節點
//cout(int i=
1;i<=n;i++
) b.map[i]
=k.map[i];}
//coutfor(
int i=
0;i<
4;i++)
b.dist=k.dist+
1;
dist[b.cantor]
=dist[k.cantor]+1
; b.come=yy[i]
; b.val=b.dist+
guess
(b);
//cout=b; q.
push
(b);
swap
(b.map[id_x]
,b.map[id_x+xx[i]])
;}return;}
intmain()
int cnt=0;
for(
int i=
1;i<=n;i++)}
}if(cnt%2==
1)first_cantor=
cantor
(use)
; p[first_cantor]
.dist=0;
p[first_cantor]
.cantor=first_cantor;
p[first_cantor]
.fa=-1
; p[first_cantor]
.come=-1
; p[first_cantor]
.val=
guess
(p[first_cantor]);
for(
int i=
1;i<=n;i++
) q.
push
(p[first_cantor]);
dist[first_cantor]=0
;while
(!q.
empty()
&&!flag)
while
(!ans.
empty()
)else
if(x==2)
else
if(x==3)
else
ans.
pop();
}printf
("\n");
}return0;
//4 7 2 3 8 6 1 x 5
//6 x 3 7 1 2 4 5 8
//5 7 4 1 8 x 2 3 6
}
八數碼問題 啟發式搜尋
一 問題描述 在乙個3 3 的方棋盤上放置著 1,2,3,4,5,6,7,8 八個數碼 每個數碼佔一格 且有乙個空格。這些數碼可以在棋盤上移動,其移動規則是 與空格相鄰的數碼方格可以移入空格。現在的問題是 對於指定的初始棋局和目標棋局,給出數碼的移動序列。該問題稱八數碼難題或者重排九宮問題。原始碼 ...
A 啟發式搜尋 八數碼問題
a 啟發式搜尋 include iostream include stdlib.h include conio.h include include define size 3 using namespace std 定義二維陣列來儲存資料表示某乙個特定狀態 typedef int status si...
八數碼問題 python實現 A 啟發式搜尋
class board object def init self self.groud 1,0,2,3,4,5,6,7,8 棋盤,0代表空 self.groud 7 2,4 5,0 6,8 3,1 移動的路徑 self.route def lt self,other return self.prio...