【圖論】【演算法】A*演算法 - 第k短路
阿新 • • 發佈:2020-07-22
用得不多,就不講那麼詳細了
功能實現
A*演算法最主要的部分就是它的估價函式\(f(i)=g(i)+h(i)\)
設\(g(i)\)為到達某點已經付出的代價,\(h(i)\)為該點到終點的估計代價
則估價函式則為兩者之和
放入優先佇列中,將會先處理估計總代價最小的狀態,以取得\(k\)短路
求從點\(st\)到點\(ed\)的第\(k\)短路的長度
如上面估價函式所需要的,我們需要先求出\(h(i)\),即預處理出圖中每個點到終點\(ed\)的估計代價(最短路徑)
對於多起點同終點型別問題,可以將有向圖中所有邊全部取反,獲得一張反向圖,然後以\(ed\)為起點跑遍整張反向圖求出最短路即可
所以此時只需要跑一邊SPFA求出\(ed\)到任意點的最短距離\(dis[i]\),即可當作正向圖中的\(h(i)\)
然後便是Astar的主要部分
建立一個新結構體\(node\)儲存搜尋過程中每一種狀態\(\{to,g(i),f(i)\}\),根據上述估價函式,過載運算子時將\(f(i)\)作為主關鍵詞,將\(g(i)\)作為次關鍵詞
從小到大排序(放入小頂堆優先佇列中),或從大到小排序(放入大頂堆優先佇列中)
以類似bfs的方法,從起點\(st\)開始搜尋,以優先佇列作為搜尋隊列
每當搜尋到一次\(ed\)點,就表明找到了一條最短路,直到第\(k\)次搜尋到\(ed\)點時,便可以直接返回當前狀態的\(g(i)\)
若在佇列為空前均沒有返回,說明不存在第\(k\)短路
程式碼
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> P; const int INF=0x3f3f3f3f; const int maxn=100050; struct node { int to,g,f; bool operator < (const node &r) const { if(r.f==f) return r.g<g; return r.f<f; } //從大到小排序,放入大頂堆內(使用時就會變成從小到大) }; vector<P> G[maxn]; //正向圖,{first,second}={to,cost} vector<P> IG[maxn]; //反向圖 bool inq[maxn]; int dis[maxn]; //dis[i]為i到ed的最短路徑 void init(int n) { for(int i=1;i<=n;i++) { G[i].clear(); IG[i].clear(); } } void SPFA(int n,int st) { queue<int> que; for(int i=1;i<=n;i++) { dis[i]=INF; inq[i]=false; } dis[st]=0; inq[st]=true; que.push(st); while(!que.empty()) { int cur=que.front(); que.pop(); inq[cur]=false; for(P &pd:IG[cur]) { if(dis[pd.first]>dis[cur]+pd.second) { dis[pd.first]=dis[cur]+pd.second; if(!inq[pd.first]) { inq[pd.first]=true; que.push(pd.first); } } } } } int AStar(int n,int st,int ed,int k) { priority_queue<node> pq; if(st==ed) k++; node tmp=node{st,0,dis[st]}; int cnt=0; pq.push(tmp); while(!pq.empty()) { node nd=pq.top(); pq.pop(); if(nd.to==ed) cnt++; //找到一條最短路 if(cnt==k) return nd.g; //當前找到的是k短路 for(P &pd:G[nd.to]) { tmp.to=pd.first; //去往的節點 tmp.g=nd.g+pd.second; //當前代價g tmp.f=tmp.g+dis[pd.first]; //估計代價f=g+h pq.push(tmp); } } return -1; } int main() { int n,m,u,v,c,st,ed,k; scanf("%d%d",&n,&m); init(n); for(int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&c); G[u].push_back(P(v,c)); IG[v].push_back(P(u,c)); } scanf("%d%d%d",&st,&ed,&k); SPFA(n,ed); printf("%d\n",AStar(n,st,ed,k)); return 0; }
實在沒找到啥非常模板的模板題,略過——