【POJ2449】第k短路
最短路是一个妇孺皆知的算法,可以用多种方法解决。但是第k短路……
以Dijkstra为例,对于s->t的第k短路,即t点在堆中第k次取出的结果。
于是我们想到了一个朴素的算法:用Dijkstra反复执行,直到t点在堆中第k次取出时结束。
考虑一下优化:用A*算法优化。
根据A*估价函数的设计原则,x->T的估计距离应当不大于x->T的实际距离,显然,我们采用x->T的最短路作为估价,这样既符合题意,又方便求解,这相当于在反向边上求解单源最短路径,在此不在赘述。
此时,我们用朴素算法求解,不同之处在于现在的Dijkstra堆中保存从起点到当前节点已经花费的代价+从当前节点到终点的最短路径(估价函数),这样再按照朴素算法求解。
A*优化后的时间复杂度最坏时与朴素算法相同(相当于估价函数的值为0),但是由于估价函数的作用,很多节点的访问次数远远小于k,因此A*优化后的算法能够较快解决问题。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 typedef long long ll; 7 inline int read() { 8 int ret=0,f=1; 9 char c=getchar(); 10 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 11 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 12 return ret*f; 13 } 14 using namespace std; 15 struct edge { 16 int next,to,dis; 17 }a[100010<<1],a1[100010<<1]; 18 int head[100010],head1[100010],num,num1; 19 int dis[1010],vis[1010],sum[1010]; 20 struct node { 21 int id,dis,val; 22 bool operator <(const node &x) const { 23 return dis+val>x.dis+x.val; 24 } 25 }; 26 priority_queue<node> q; 27 priority_queue< pair<int,int> >qq; 28 int n,m,k,s,t; 29 inline void add(int from,int to,int dis) { 30 a[++num].next=head[from]; 31 a[num].to=to; 32 a[num].dis=dis; 33 head[from]=num; 34 } 35 inline void add1(int from,int to,int dis) { 36 a1[++num1].next=head1[from]; 37 a1[num1].to=to; 38 a1[num1].dis=dis; 39 head1[from]=num1; 40 } 41 int main() { 42 n=read(); m=read(); 43 for(int i=1,x,y,z;i<=m;i++) { 44 x=read(); y=read(); z=read(); 45 add(x,y,z); 46 add1(y,x,z); 47 } 48 s=read(); t=read(); k=read(); 49 if(s==t) k++; 50 memset(dis,0x3f,sizeof(dis)); 51 dis[t]=0; 52 qq.push(make_pair(0,t)); 53 while(!qq.empty()) { 54 int now=qq.top().second; 55 qq.pop(); 56 if(vis[now]) continue ; 57 vis[now]=1; 58 for(int i=head1[now];i;i=a1[i].next) 59 if(dis[a1[i].to]>dis[now]+a1[i].dis) { 60 dis[a1[i].to]=dis[now]+a1[i].dis; 61 qq.push(make_pair(-dis[a1[i].to],a1[i].to)); 62 } 63 } 64 node noww; 65 noww.id=s; 66 noww.val=0; 67 noww.dis=dis[s]; 68 q.push(noww); 69 while(!q.empty()) { 70 node now=q.top(); 71 q.pop(); 72 sum[now.id]++; 73 if(sum[now.id]>k) continue ; 74 if(now.id==t&&sum[now.id]==k) { 75 printf("%d\n",now.val); 76 return 0; 77 } 78 for(int i=head[now.id];i;i=a[i].next) { 79 node neww; 80 neww.id=a[i].to; neww.dis=dis[a[i].to]; 81 neww.val=now.val+a[i].dis; 82 q.push(neww); 83 } 84 } 85 puts("-1"); 86 return 0; 87 }