1. 程式人生 > >K短路問題模板(spfa+A*)

K短路問題模板(spfa+A*)

k短路問題

給一個圖,起點s、終點t、k,求起點到終點的第k短路。
基本思路:
首先spfa求出反向圖中求出終點t到其他所有點的距離(預處理)
再從起點開始使用優先佇列進行寬搜,用cnt記錄到達終點的次數,當cnt==k時的路徑長度即為所得。
搜尋的方向用一個估價函式f=g+dis來確定,其中g表示起點到當前點的路徑長度,dis表示當前點到終點的最短路徑(即之前的預處理),每次擴充套件估價函式值最小的一個。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std
; const int maxn=100010; int n,m,dis[maxn]; int tot,head1[maxn],head2[maxn]; bool flag[maxn]; struct edge { int to; int w; int next; }e[maxn*2],e2[maxn*2]; struct node { int f;//f=g+dis dis表示當前點到終點的最短路徑,即之前的預處理 int g;//g表示到當前點的路徑長度 int from; bool operator < (node a)const { if
(a.f==f) return g>a.g;//過載 小的在前面 return f>a.f; } }; void add_edge(int u,int v,int w) { tot++; e[tot].to=v; e[tot].w=w; e[tot].next=head1[u]; head1[u]=tot; e2[tot].to=u;//建反圖 e2[tot].w=w; e2[tot].next=head2[v]; head2[v]=tot; } void spfa(int t)//反圖預處理dis
{ for(int i=1;i<=n;i++) dis[i]=maxn; dis[t]=0; queue<int> q; q.push(t); flag[t]=1; while(!q.empty()) { int v=q.front(); q.pop();flag[v]=0; for(int i=head2[v];i;i=e2[i].next) if(dis[e2[i].to]>dis[v]+e2[i].w) { dis[e2[i].to]=dis[v]+e2[i].w; if(!flag[e2[i].to]) { q.push(e2[i].to); flag[e2[i].to]=1; } } } } int a_star(int s,int t,int k) { if(s==t) return 0; if(dis[s]==maxn) return -1; priority_queue<node> q; int cnt=0; node tmp,to; tmp.from=s; tmp.g=0; tmp.f=tmp.g+dis[tmp.from]; q.push(tmp); while(!q.empty()) { tmp=q.top(); q.pop(); if(tmp.from==t) cnt++; if(cnt==k) return tmp.g; for(int i=head1[tmp.from];i;i=e[i].next) { to.from=e[i].to; to.g=tmp.g+e[i].w; to.f=to.g+dis[to.from]; q.push(to); } } return -1; } int main() { int x,y,z,s,t,k; cin>>n>>m; for(int i=1;i<=m;i++) { cin>>x>>y>>z; add_edge(x,y,z); } cin>>s>>t>>k;//輸入起點,終點,k短路 spfa(t); int ans=a_star(s,t,k); cout<<ans; return 0; }