AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 178. 【算法提高课】第\text K短路(A*+Dijkstra)    原题链接    困难

作者: 作者的头像   incra ,  2022-11-08 18:01:50 ,  所有人可见 ,  阅读 1797


29


2

<—点个赞吧QwQ

宣传一下算法提高课整理

给定一张 $N$ 个点(编号 $1,2…N$),$M$ 条边的有向图,求从起点 $S$ 到终点 $T$ 的第 $K$ 短路的长度,路径允许重复经过点或边。

注意: 每条最短路中至少要包含一条边。

输入格式

第一行包含两个整数 $N$ 和 $M$。

接下来 $M$ 行,每行包含三个整数 $A,B$ 和 $L$,表示点 $A$ 与点 $B$ 之间存在有向边,且边长为 $L$。

最后一行包含三个整数 $S,T$ 和 $K$,分别表示起点 $S$,终点 $T$ 和第 $K$ 短路。

输出格式

输出占一行,包含一个整数,表示第 $K$ 短路的长度,如果第 $K$ 短路不存在,则输出 $\-1$。

数据范围

$1 \\le S,T \\le N \\le 1000$,
$0 \\le M \\le 10^4$,
$1 \\le K \\le 1000$,
$1 \\le L \\le 100$

输入样例:

2 2
1 2 5
2 1 4
1 2 2

输出样例:

14

思路

  1. 第$ K $短路,就是终点出队$ K $次的距离。注意:当起点和终点一样时,$K ++$
  2. 只要从$ S $能到达$ T$,就一定存在第K短路,故不存在则一定不能从$ S $到达$ T$
  3. 估价函数:从该点到终点的最短距离,即求一遍$ \text{Dijkstra}$,大于等于$ 0$,小于等于真实值
  4. 取出堆顶,记录出队次数,把该点能枚举到的所有点都放入小根堆

代码

#include <iostream>
#include <cstring>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair <int,int> PII;
typedef pair <int,PII> PIII;
const int N = 1010,M = 200010;
int n,m,S,T,K;
int h[N],rh[N],e[M],w[M],ne[M],idx;
int dist[N],cnt[N];
bool st[N];
void add (int h[],int a,int b,int c) {
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx++;
}
void dijkstra () {
    priority_queue <PII,vector <PII>,greater <PII>> heap;
    heap.push ({0,T});
    memset (dist,0x3f,sizeof (dist));
    dist[T] = 0;
    while (heap.size ()) {
        auto t = heap.top ();
        heap.pop ();
        int ver = t.y;
        if (st[ver]) continue;
        st[ver] = true;
        for (int i = rh[ver];~i;i = ne[i]) {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i]) {
                dist[j] = dist[ver] + w[i];
                heap.push ({dist[j],j});
            }
        }
    }
}
int Astar () {
    priority_queue <PIII,vector <PIII>,greater <PIII>> heap;
    heap.push ({dist[S],{0,S}});
    while (heap.size ()) {
        auto t = heap.top ();
        heap.pop ();
        int ver = t.y.y,distance = t.y.x;
        cnt[ver]++;
        if (cnt[T] == K) return distance;
        for (int i = h[ver];~i;i = ne[i]) {
            int j = e[i];
            if (cnt[j] < K) heap.push ({distance+w[i]+dist[j],{distance+w[i],j}});
        }
    }
    return -1;
}
int main () {
    memset (h,-1,sizeof (h));
    memset (rh,-1,sizeof (rh));
    cin >> n >> m;
    for (int i = 0;i < m;i++) {
        int a,b,c;
        cin >> a >> b >> c;
        add (h,a,b,c);
        add (rh,b,a,c);
    }
    cin >> S >> T >> K;
    if (S == T) K++;
    dijkstra ();
    cout << Astar () << endl;
    return 0;
}

13 评论


用户头像
I_wanna_be_accepted   2023-02-14 10:12      2    踩      回复

你们怎么都不解释 if(cnt[j]<k) qwq

用户头像
incra   2023-03-30 19:27         踩      回复

因为很好懂啊,就是出对次数<k时更新

用户头像
Silvervale   2023-05-02 21:29    回复了 incra 的评论         踩      回复

为什么出对次数>k时就不用更新了?这里没懂

用户头像
incra   2023-05-03 07:38    回复了 Silvervale 的评论         踩      回复

出队第k次就代表找到答案了

用户头像
Guo-yyds   2023-05-07 18:40    回复了 incra 的评论      1    踩      回复

但是yxc视频里面说 不是终点 可以大于k次

用户头像
incra   2023-05-08 17:26    回复了 Guo-yyds 的评论         踩      回复

那按y总说的算

用户头像
Guo-yyds   2023-05-08 17:27    回复了 incra 的评论         踩      回复

hh

用户头像
incra   2023-05-08 17:59    回复了 Guo-yyds 的评论         踩      回复

的确,这个讲理论确实海涩
其实是我太菜了

用户头像
糖豆   2023-06-20 16:40    回复了 incra 的评论      3    踩      回复

不是你太菜了,是那块本来讲的就不太明白,我说下我的理解:

此处代码有两种写法:
网上大神写法:

for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (cnt[v] < K)
                q.push({v, d + w[i], d + w[i] + dist[v]});
        }

我的写法:

  for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (dist[v] < INF)                             // 如果是无效借力点,跳过
                q.push({v, d + w[i], d + w[i] + dist[v]}); // 点,距离,估值函数值
        }

原因:见$AcWing$给出错误时的数据用例:

#### 感悟
① 自我认为我的办法才是正解,因为你想把估值函数入队列,还指望着函数值小的优先,那如果d + w[i] + dist[v]>=INF,再往里放就是无效操作,而dist[v]是有可能等于INF的,因为
$$\large S->v-\ngtr T$$
此时,$v$就是 一个无效转移点,不用入队列,一次都不用!
② 通过错误的 数据用例 来反思、推导,加深理解非常重要,此处给$AcWing$满分,比某谷要强的多!与学会自我创造测试用例一样有用,在以后的学习中一次要重视起来。

用户头像
incra   2023-06-20 17:33    回复了 糖豆 的评论         踩      回复

不错,tql %%%
orz


用户头像
AcWing_CMS   2025-04-12 15:56 · 山东         踩      回复

$\Large\color{blue}{【算法提高课】第\text K短路(\text A^*+\text{Dijkstra})}$


用户头像
sentimental   2023-05-24 21:04         踩      回复

hh tql


用户头像
可爱抱抱呀   2023-03-28 12:39         踩      回复

k大于1 的时候,但是t没有出边,那么也没有答案


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息