【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 }
AC Code

 

转载于:https://www.cnblogs.com/shl-blog/p/10627799.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值