<学习笔记> A*算法求第k短路
简洁题面
- 第一行给出N(点数),M(边数)(1 <= N <= 1000, 0 <= M <= 100000).。
- 下面的M行每行给出三个数Ai,Bi,Ti,表示从A到B有一条权值为T的单向边。
- 最后给出S,T,K,表示求S到T的第K短路。
- special:
- 起点与终点相同时,S–>S (d=0) 不能算作一条路。
- 题目会给出多组数据。
- 即使有好几条路到T的距离都相同,它们仍被记为不同的路。
正解
A*算法
记g[i]为起点s到i的距离,h[i] (期望值)为终点T到i的最短路,用SPFA预处理出来。采用dijkstra的做法,从S开始处理,每次从堆中弹出当前h[i]+g[i]最小的点。当终点T被弹出第K次时,此时的g[i]即为S到T的第K短路。
代码qwq
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 9 int N,M,a,b,c,S,T,K,cnt; 10 int first[1010],next[100010],h[1010]; 11 bool used[1010]; 12 13 struct maple{ 14 int f,t,d; 15 }Rode[100010]; 16 17 struct leaf{ 18 int f,g,h; 19 bool operator <(const leaf &a) const{ 20 return a.g+a.h<g+h; 21 } 22 }; 23 24 void Build(int f,int t,int d) 25 { 26 Rode[++cnt]=(maple){f,t,d}; 27 next[cnt]=first[f]; 28 first[f]=cnt; 29 } 30 31 void SPFA() 32 { 33 queue<int> q; // 34 memset(h,63,sizeof(h)); 35 memset(used,0,sizeof(used)); 36 h[T]=0; 37 used[T]=1; 38 q.push(T); 39 while(!q.empty()) 40 { 41 int A=q.front(); 42 q.pop(); 43 used[A]=0; 44 for(int i=first[A];i;i=next[i]) 45 if(h[Rode[i].t]>h[A]+Rode[i].d) 46 { 47 h[Rode[i].t]=h[A]+Rode[i].d; 48 if(!used[Rode[i].t]) 49 { 50 used[Rode[i].t]=1; 51 q.push(Rode[i].t); 52 } 53 } 54 } 55 } 56 57 int search() 58 { 59 if(h[S]>1e9+7) return -1; // 从起点无法到终点 60 if(S==T) ++K; 61 priority_queue<leaf> Q; // 定义在函数里不用清空qwq 62 Q.push((leaf){S,0,h[S]}); 63 while(!Q.empty()) 64 { 65 leaf A=Q.top(); 66 Q.pop(); 67 if(A.f==T) 68 { 69 --K; 70 if(K==0) return A.g; 71 } 72 for(int i=first[A.f];i;i=next[i]) 73 Q.push((leaf){Rode[i].t,A.g+Rode[i].d,h[Rode[i].t]}); 74 } 75 return -1; // 没找到第k短路也不行 76 } 77 int main() 78 { 79 while(scanf("%d%d",&N,&M)!=EOF) 80 { 81 cnt=0; 82 memset(first,0,sizeof(first)); 83 memset(next,0,sizeof(next)); 84 for(int i=1;i<=M;++i) 85 { 86 scanf("%d%d%d",&a,&b,&c); 87 Build(b,a,c); 88 } 89 scanf("%d%d%d",&S,&T,&K); 90 SPFA(); 91 memset(first,0,sizeof(first)); 92 memset(next,0,sizeof(next)); 93 cnt=0; 94 for(int i=1;i<=M;++i) 95 Build(Rode[i].t,Rode[i].f,Rode[i].d); // 重新建边 96 int ans=search(); 97 printf("%d\n",ans); 98 } 99 return 0; 100 }