题意就是要求第K短的路的长度(S->T)。
对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度。
但是这种方法效率太低,会扩展出很多状态,所以考虑用启发式搜索A*算法。
估价函数 = 当前值 + 当前位置到终点的距离,即F(p) = G(p) + H(p)。
G(p): 当前从S到p所走的路径距离
H(p): 当前点p到终点T的最短路径距离 ---可以先将整个图边方向取反然后以T为源点求个最短路,用SPFA提速
F(p): 从S按照当前路径走到p然后走到T一共至少走多远
所以我们结合SPFA+A*可以解决。
注意:当S==T时,需要计算第K+1短路,因为从S->T这条长度为0的路径不能算在内。
还有,SPFA处判了一下负环。SPFA算法中,如果某个点出队次数大于n,说明此处存在负环。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <functional> #define Mod 1000000007 using namespace std; #define N 1007 struct node { int v; int g,f; //f = g+h bool operator < (const node &a)const { if(a.f == f) return a.g < g; return a.f < f; } }; struct Edge { int v,w,next; }G[100*N],G2[100*N]; int head[100*N],head2[100*N]; int vis[N],dis[N]; int out[N]; int n,m,K,S,T,tot,tot2; void addedge(Edge *G,int& tot,int *head,int u,int v,int w) { G[tot].v = v; G[tot].w = w; G[tot].next = head[u]; head[u] = tot++; } int SPFA(int s,int head[N],Edge G[N],int dis[N]) { int i; queue<int> que; for(i=0;i<=n;i++) dis[i] = Mod; memset(vis,0,sizeof(vis)); memset(out,0,sizeof(out)); que.push(s); vis[s] = 1; dis[s] = 0; while(!que.empty()) { int now = que.front(); que.pop(); vis[now] = 0; out[now]++; if(out[now] > n) return 0; for(int k=head[now];k!=-1;k=G[k].next) { if(dis[G[k].v] > dis[now] + G[k].w) { dis[G[k].v] = dis[now] + G[k].w; if(!vis[G[k].v]) { vis[G[k].v] = 1; que.push(G[k].v); } } } } return 1; } int A_Star(int head[N],Edge G[N],int dis[N]) { node tmp,now; int cnt = 0; priority_queue<node> que; if(S == T) K++; if(dis[S] == Mod) return -1; tmp.v = S; tmp.g = 0; tmp.f = tmp.g+dis[S]; que.push(tmp); while(!que.empty()) { tmp = que.top(); que.pop(); if(tmp.v == T) cnt++; if(cnt == K) return tmp.g; for(int i=head[tmp.v];i!=-1;i=G[i].next) { now.v = G[i].v; now.g = tmp.g + G[i].w; now.f = now.g + dis[now.v]; que.push(now); } } return -1; } int main() { int i,j,u,v,w; while(scanf("%d%d",&n,&m)!=EOF) { memset(head,-1,sizeof(head)); memset(head2,-1,sizeof(head2)); tot = tot2 = 1; for(i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&w); addedge(G,tot,head,u,v,w); //原图 addedge(G2,tot2,head2,v,u,w); //反图 } scanf("%d%d%d",&S,&T,&K); if(SPFA(T,head2,G2,dis)) { int k_len = A_Star(head,G,dis); printf("%d\n",k_len); } else puts("-1"); } return 0; }