题意:求有向图从s点到t点的第k短路,每个点可以重复经过。
解法:建一个正向图和一个反向图,先用Dijkstra求出反向图中从t点到其他点的最短距离dis,再用A*算法求出第k短路。
A*求第k短路的方法:与Dijkstra算法类似,设结点nd(u,g)表示当前所在点为u且从s到u经过的长度为g的结点(路径),则以g+dis[u]为权值放进优先队列,每次选择权值最小的结点进行扩展,直至t点第k次出队。
算是A*算法的一道入门题吧。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 5 using namespace std; 6 const int N=1000+10,M=1e5+10; 7 const int inf=0x3f3f3f3f; 8 struct E { 9 int v,c,nxt; 10 } e[M<<1]; 11 int head1[N],head2[N],dis[N],vis[N],ne; 12 int n,m; 13 14 struct cmp { 15 bool operator()(int a,int b)const { 16 return dis[a]>dis[b]; 17 } 18 }; 19 20 struct nd { 21 int u,g; 22 bool operator<(const nd& b)const { 23 return g+dis[u]>b.g+dis[b.u]; 24 } 25 }; 26 27 void Dij(int s) { 28 priority_queue<int,vector<int>,cmp> q; 29 memset(vis,0,sizeof vis); 30 memset(dis,inf,sizeof dis); 31 dis[s]=0; 32 q.push(s); 33 while(!q.empty()) { 34 int u=q.top(); 35 q.pop(); 36 if(vis[u])continue; 37 vis[u]=1; 38 for(int i=head2[u]; ~i; i=e[i].nxt) { 39 int v=e[i].v,c=e[i].c; 40 if(dis[u]+c<dis[v]) { 41 dis[v]=dis[u]+c; 42 q.push(v); 43 } 44 } 45 } 46 } 47 48 int Astar(int s,int t,int k) { 49 int cnt=0; 50 if(s==t)cnt--; 51 priority_queue<nd> q; 52 q.push({s,0}); 53 while(!q.empty()) { 54 int u=q.top().u,g=q.top().g; 55 q.pop(); 56 if(u==t)++cnt; 57 if(cnt==k)return g; 58 for(int i=head1[u]; ~i; i=e[i].nxt) { 59 int v=e[i].v,c=e[i].c; 60 q.push({v,g+c}); 61 } 62 } 63 return -1; 64 } 65 66 int main() { 67 memset(head1,-1,sizeof head1); 68 memset(head2,-1,sizeof head2); 69 ne=0; 70 scanf("%d%d",&n,&m); 71 while(m--) { 72 int u,v,c; 73 scanf("%d%d%d",&u,&v,&c); 74 e[ne]=(E) {v,c,head1[u]},head1[u]=ne++; 75 e[ne]=(E) {u,c,head2[v]},head2[v]=ne++; 76 } 77 int s,t,k; 78 scanf("%d%d%d",&s,&t,&k); 79 Dij(t); 80 printf("%d ",Astar(s,t,k)); 81 return 0; 82 }