搜索 —— 启发式搜索 —— A* 算法
【概述】
A*(A-Star)算法是一種在靜態(tài)路網(wǎng)中,求解最短路的最有效的直接搜索方法,也是解決許多搜索問(wèn)題的有效算法之一。
A* 算法實(shí)際上是對(duì) Dijkstra 算法的優(yōu)化后得到的,關(guān)于 Dijkstra 算法:點(diǎn)擊這里
A*算法在程序設(shè)計(jì)競(jìng)賽中,一般用于解決 k 短路問(wèn)題,關(guān)于 k 短路問(wèn)題:點(diǎn)擊這里
【原理】
在 Dijkstra 算法中,我們借助優(yōu)先隊(duì)列來(lái)實(shí)現(xiàn),每次從優(yōu)先隊(duì)列中取出結(jié)點(diǎn),再?gòu)倪@個(gè)結(jié)點(diǎn)擴(kuò)散到其他結(jié)點(diǎn),而優(yōu)先隊(duì)列的優(yōu)先依據(jù)是根據(jù)起點(diǎn)到隊(duì)列中結(jié)點(diǎn)最近的一個(gè),即隊(duì)列中的結(jié)點(diǎn)離起始點(diǎn)最近的會(huì)先出隊(duì)。
但不可避免的是,Dijkstra 存在跑偏問(wèn)題,如下圖,若起點(diǎn)為 1 號(hào)點(diǎn),終點(diǎn)為 6 號(hào)點(diǎn),首先一定會(huì)走 3、4 號(hào)點(diǎn),這肯定不是最佳路徑,一開始就跑偏了。
在 Dijkstra 算法中,判斷的依據(jù)只是已知的起點(diǎn)到某點(diǎn) i 的距離 G(i),那么我們可以增加一個(gè)判斷量來(lái)減少跑偏的概率。
如果能夠計(jì)算當(dāng)前點(diǎn) i 到終點(diǎn)的距離,再結(jié)合 G(i),那么可以防止過(guò)度跑偏,但這個(gè)距離是未知的,因此我們可以設(shè)置一個(gè)估值,即啟發(fā)函數(shù) H(i)。
啟發(fā)函數(shù) H(i) 的設(shè)置是 A* 算法關(guān)鍵,如何設(shè)置這個(gè)啟發(fā)函數(shù)影響到算法的性能,在得到了啟發(fā)函數(shù)后,我們就有了最終的估價(jià)函數(shù) F(i)=G(i)+H(i),在優(yōu)先隊(duì)列中,以這個(gè)估價(jià)函數(shù)作為指標(biāo)進(jìn)行出隊(duì)。
一般來(lái)說(shuō),在二維平面圖中,我們將圖置于坐標(biāo)軸中,通過(guò)計(jì)算結(jié)點(diǎn)間的歐幾里得距離來(lái)得到兩點(diǎn)間的直線距離,這個(gè)距離即可作為當(dāng)前點(diǎn) i 到終點(diǎn)距離的估值。但歐幾里得距離的計(jì)算要進(jìn)行開方,較為復(fù)雜,一般通過(guò)加減法來(lái)計(jì)算簡(jiǎn)單的曼哈頓距離來(lái)代替歐幾里得距離,作為啟發(fā)函數(shù) H(i)。
而在一般圖中,我們通常是建立反圖,跑一次最短路算法,將得到每個(gè)點(diǎn)到 t?的最短路的距離 dis[i] 作為啟發(fā)函數(shù) H(i)
【實(shí)現(xiàn)】
struct Edge {int to, next;int w;Edge() {}Edge(int to, int next, int w) : to(to), next(next), w(w) {} }; struct Map {int tot;int head[N];Edge edge[N * N];Map() {tot = 0;memset(head, -1, sizeof(head));}void addEdge(int x, int y, int w) {edge[++tot].to = y;edge[tot].next = head[x];edge[tot].w = w;head[x] = tot;}Edge &operator[](int pos) { return edge[pos]; } }; int n, m; Map G, GT; int dis[N]; bool vis[N]; struct Status{int node;//點(diǎn)編號(hào)int diss;//距離int priority;//優(yōu)先級(jí)Status() : node(0), diss(0), priority(dis[0]) {}Status(int node, int diss) : node(node), diss(diss), priority(diss + dis[node]) {}bool operator<(Status b) const { return priority > b.priority; } } status; bool SPFA(int S, int T) { //對(duì)反圖求最短路memset(dis, INF, sizeof(dis));memset(vis, false, sizeof(vis));dis[S] = 0;queue<int> Q;Q.push(S);while (!Q.empty()) {int x = Q.front();Q.pop();vis[x] = false;for (int i = GT.head[x]; i != -1; i = GT[i].next) {int y = GT[i].to;if (dis[x] + GT[i].w < dis[y]) {dis[y] = dis[x] + GT[i].w;if (!vis[y]) {Q.push(y);vis[y] = true;}}}}return dis[T] != INF; } int AStar(int S, int T) {priority_queue<Status> Q;Q.push(Status(S, 0));while (!Q.empty()) {Status temp = Q.top();Q.pop();if (temp.node == T)return temp.diss;for (int i = G.head[temp.node]; i != -1; i = G[i].next)if (temp.diss + G[i].w < temp.diss)Q.push(Status(G[i].to, temp.diss + G[i].w));}return -1; } int main() {scanf("%d%d", &n, &m);for (int i = 1; i <= m; i++) {int x, y, w;scanf("%d%d%d", &x, &y, &w);G.addEdge(x, y, w);GT.addEdge(y, x, w);}int s, t;scanf("%d%d", &s, &t);if (!SPFA(t, s))printf("-1\n");elseprintf("%d\n", AStar(s, t));return 0; }?
總結(jié)
以上是生活随笔為你收集整理的搜索 —— 启发式搜索 —— A* 算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 天堂里的游戏(51Nod-1417)
- 下一篇: 树形结构 —— 树与二叉树 —— 树的直