求圖的第K短路(A*演算法與最短路的應用)
阿新 • • 發佈:2019-01-27
前言:最短路演算法是我們非常熟悉的了。Dijkstra,SPFA等單源最短路演算法是我們在競賽中常用的演算法。那麼,假如題目要求的不是最短的呢?
Question(1):給定一個圖,求次短路。
對於次短路,很容易想到在比較的時候進行處理。
設dis(u)為原點s到u的最短路徑,u為當前節點,v和u有邊相連。
x = dis[v] + f[u][v];
則對於最短路:if(dis[u] > x) dis[u] = x;
而對於次短路:
if(dis[u]>x) dis2[u]=dis[u],dis[u]=x;
else if(dis2[u]>x) dis2[u]=x;
所以,對於次短路,只需加多一個數組即可。
那麼,K短路呢?
Question(2):給定一個圖,求第K短路。
對於這個問題,可以用A*演算法+Dijkstra解決。
先了解一下A*演算法:
A*演算法是一種典型的啟發式搜尋演算法。定義:
h*(s)為狀態s到目標的距離
h(s)為估價函式,狀態s到目標距離的下界,即h(s)<=h*(s)
g(s)為到達狀態s所需的代價
f(s)為s的啟發函式。有f(s) = h(s) + g(s)。
那麼,對於本題:h(s)就是源點到s的距離,g(s)為到終點t的實際距離。
如果能求出g,那麼,當A*搜尋了終點k次後,當前的h就為答案。
求函式g的方法:因為g(s)為到終點t的實際距離,所以,可以把原圖的邊反向後,把終點改成源點,跑一次Dijkstra,算出每一個點u到t的距離,就是所求的g。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <cstdlib> #include <stack> #include <queue> #include <map> #include <set> using namespace std; #define Maxn 10010 #define INF 1000000000 struct node{ int to,val; node() {} node(int a,int b) { to = a; val = b; } }; vector<node> adj[Maxn],_adj[Maxn]; int n,m,k; bool vis[Maxn]; int dis[Maxn]; void AddEdge(int x,int y,int val) { adj[x].push_back(node(y,val)); _adj[y].push_back(node(x,val));//把圖反向 } void Dijkstra(int s,int t) { priority_queue<int , vector<int> , greater<int> > q; while(!q.empty()) q.pop(); for(int i=1;i<=n;i++) vis[i] = false,dis[i] = INF; vis[t] = true; dis[t] = 0; q.push(t); int u,len; while(!q.empty()) { u = q.top(); q.pop(); len = _adj[u].size(); for(int i=0;i<len;i++) { node v = _adj[u][i]; if(dis[v.to] > dis[u] + v.val) { dis[v.to] = dis[u] + v.val; if(!vis[v.to]) { q.push(v.to); vis[v.to] = true; } } } vis[u] = false; } } struct Anode{ int h,g,id; Anode(int a,int b,int c) {h=a; g=b; id=c;} bool operator < (Anode a) const { return h+g > a.h+a.g; } }; priority_queue<Anode> Q; int Astar(int s,int t)//A*演算法過程 { while(!Q.empty()) Q.pop(); Q.push(Anode(0,dis[s],s)); int len,num; num = 0; while(!Q.empty()) { Anode u = Q.top(); Q.pop(); if(u.id==t) ++num; if(num>=k) return u.h; len = adj[u.id].size(); for(int i=0;i<len;i++) { node v = adj[u.id][i]; Q.push(Anode(u.h+v.val,dis[v.to],v.to)); } } return -1;//不能連通或者沒有第K短路 } int main() { while(scanf("%d%d",&n,&m)!=-1) { for(int i=0;i<Maxn;i++) adj[i].clear(),_adj[i].clear(); int x,y,v,s,t; for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&v); AddEdge(x,y,v); } scanf("%d%d%d",&s,&t,&k); if(s==t) k++; Dijkstra(s,t); printf("%d\n",Astar(s,t)); } return 0; }