每周一算法:单源次短路

题目描述

“您的个人假期”旅行社组织了一次比荷卢经济联盟的巴士之旅。

比荷卢经济联盟有很多公交线路。每天公共汽车都会从一座城市开往另一座城市。沿途汽车可能会在一些城市(零或更多)停靠。

旅行社计划旅途从 S S S 城市出发,到 F F F 城市结束。由于不同旅客的景点偏好不同,所以为了迎合更多旅客,旅行社将为客户提供多种不同线路。游客可以选择的行进路线有所限制,要么满足所选路线总路程为 S S S F F F 的最小路程,要么满足所选路线总路程仅比最小路程多一个单位长度。

在这里插入图片描述
如上图所示,如果 S = 1 S=1 S=1 F = 5 F=5 F=5,则这里有两条最短路线 1 → 2 → 5 , 1 → 3 → 5 1→2→5,1→3→5 125,135,长度为 6 6 6
;有一条比最短路程多一个单位长度的路线 1 → 3 → 4 → 5 1→3→4→5 1345,长度为 7 7 7

现在给定比荷卢经济联盟的公交路线图以及两个城市 S S S F F F,请你求出旅行社最多可以为旅客提供多少种不同的满足限制条件的线路。

输入格式

第一行包含整数 T T T,表示共有 T T T 组测试数据。

每组数据第一行包含两个整数 N N N M M M,分别表示总城市数量和道路数量。

接下来 M M M 行,每行包含三个整数 A , B , L A,B,L A,B,L,表示有一条线路从城市 A A A 通往城市 B B B,长度为 L L L

需注意,线路是单向的,存在从 A A A B B B 的线路不代表一定存在从 B B B A A A 的线路,另外从城市 A A A 到城市 B B B 可能存在多个不同的线路。

接下来一行,包含两个整数 S S S F F F,数据保证 S S S F F F 不同,并且 S S S F F F 之间至少存在一条线路。

输出格式

每组数据输出一个结果,每个结果占一行。

数据保证结果不超过 1 0 9 10^9 109

样例 #1

样例输入 #1

2
5 8
1 2 3
1 3 2
1 4 5
2 3 1
2 5 3
3 4 2
3 5 4
4 5 3
1 5
5 6
2 3 1
3 2 1
3 1 10
4 5 2
5 2 7
5 2 7
4 1

样例输出 #1

3
2

提示

【数据范围】

2 ≤ N ≤ 1000 2≤N≤1000 2N1000,
1 ≤ M ≤ 10000 1≤M≤10000 1M10000,
1 ≤ L ≤ 1000 1≤L≤1000 1L1000
1 ≤ A , B , S , F ≤ N 1≤A,B,S,F≤N 1A,B,S,FN

算法思想

根据题目描述,求的是从 S S S 城市出发、到 F F F 城市结束的所有路线中,最短路、或者仅比最小路程多 1 1 1个单位长度的次短路的方案数。

在博主的另一篇文章每周一算法:最短路计数介绍过,可以使用动态规划的思想,定义状态 f [ i ] f[i] f[i]表示起点到顶点 i i i的最短路的方案数。为了能同时求出次短路的方案数,可以采用拆点的思想:

  • f [ i ] [ 0 ] f[i][0] f[i][0]表示起点到顶点 i i i的最短路的方案数
  • f [ i ] [ 1 ] f[i][1] f[i][1]表示起点到顶点 i i i的次短路的方案数

与最短路计数一样,图中有可能存在环,不一定存在拓扑序列,因此不能通过循环迭代直接计算状态;可以使用最短路算法,在计算最短路的同时将状态计算出来。同时,在计算最短路时,能够找到一个拓扑序来计算状态。这样就需要最短路算法能够构造出一个最短路拓扑图,如下图所示:
在这里插入图片描述
由于边权不相同,这里可以用Dijkstra算法求最短路。Dijkstra算法计算最短路时,每个点只会出队 1 1 1次,当一个点出队时,是不会更新前面已经出队的点到起点的最短路,因此出队序列满足拓扑序。

算法流程

  • 将起点 S S S的最短路初始化为 0 0 0,即 d i s [ S ] [ 0 ] = 0 dis[S][0]=0 dis[S][0]=0;方案数初始化为 1 1 1,即 f [ S ] [ 0 ] = 1 f[S][0] = 1 f[S][0]=1
  • 在求解最短路的过程中
    • v v v点到起点的最短路能够被点松弛:
      • 将之前的最短路变为次短路,更新次短路的方案数
      • 更新最短路的长度,设置最短路的方案数
    • v v v点到起点的最短路等于经过 u u u点中转的距离,累加最短路的方案数
    • v v v点到起点的次短路能够被点松弛:
      • 更新次短路的长度,设置次短路的方案数
    • v v v点到起点的次短路等于经过 u u u点中转的距离,累加次短路的方案数
  • 最后,如果次短路的长度 + 1 +1 +1等于最短路长度,即 d i s [ F ] [ 1 ] = d i s [ F ] [ 0 ] + 1 dis[F][1] = dis[F][0] + 1 dis[F][1]=dis[F][0]+1,那么总方案数为 f [ F ] [ 0 ] + f [ F ] [ 1 ] f[F][0]+f[F][1] f[F][0]+f[F][1];否则,总方案数为 f [ F ] [ 0 ] f[F][0] f[F][0]

代码实现

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 1e4 + 5;
int h[N], e[M], w[M], ne[M], idx; 
int n, m, S, F;
int dis[N][2], f[N][2]; //f[i][0]表示到i点最短路条数
bool st[N][2];
struct V {int ver, type, dis; //节点、类型(0最短路、1次短路)、到起点距离bool operator > (const V &v) const //小顶堆,重载 > {return dis > v.dis;}
};
void add(int a, int b, int c)
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
int dijkstra()
{memset(st, 0, sizeof st);memset(dis, 0x3f, sizeof dis);memset(f, 0, sizeof f);dis[S][0] = 0, f[S][0] = 1; //初始化最短路和条数priority_queue<V, vector<V>, greater<V>> q; //小顶堆q.push({S, 0, 0}); //起点最短路入堆while(q.size()){V t = q.top(); q.pop();int u = t.ver, type = t.type, d = t.dis, cnt = f[u][type];if(st[u][type]) continue;st[u][type] = true;for(int i = h[u]; ~ i; i = ne[i]){int v = e[i];if(dis[v][0] > d + w[i]) //可以更新最短路{dis[v][1] = dis[v][0], f[v][1] = f[v][0]; //最短路变次短路,同时更新次短路个数q.push({v, 1, dis[v][1]}); //次短路入堆dis[v][0] = d + w[i], f[v][0] = cnt; //更新最短路以及最短路个数q.push({v, 0, dis[v][0]});}else if(dis[v][0] == d + w[i]) //与最短路相等{f[v][0] += cnt; //累加最短路个数}else if(dis[v][1] > d + w[i]) //可以更新次短路{dis[v][1] = d + w[i], f[v][1] = cnt;q.push({v, 1, dis[v][1]});}else if(dis[v][1] == d + w[i]) //与次短路相等{f[v][1] += cnt;}}}int ans = f[F][0]; //最短路个数if(dis[F][1] == dis[F][0] + 1) //次短路等于最短路+1ans += f[F][1];return ans;
}
int main()
{int T;scanf("%d", &T);while(T --){scanf("%d%d", &n, &m);memset(h, -1, sizeof h);idx = 0;while(m --){int a, b, c;scanf("%d%d%d", &a, &b, &c);add(a, b, c);}scanf("%d%d", &S, &F);printf("%d\n", dijkstra());}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/4997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言进阶|链表经典OJ题

✈移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 方法一&#xff1a; 遍历链表找到所有等于val的节点&#xff0c;再执行删除操作删除这些节点。 方法二&#xff1a; …

算法必备数学基础:图论方法由浅入深实践与应用

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 python数据分析…

SparkSQL---简介及RDD V.S DataFrame V.S Dataset编程模型详解

一、SparkSQL简介 SparkSQL&#xff0c;就是Spark生态体系中的构建在SparkCore基础之上的一个基于SQL的计算模块。SparkSQL的前身不叫SparkSQL&#xff0c;而叫Shark&#xff0c;最开始的时候底层代码优化&#xff0c;sql的解析、执行引擎等等完全基于Hive&#xff0c;总之Sha…

2024年水资源保护盛事,“澜湄周”邀请国信华源加入!

4月26日&#xff0c;2024年水资源领域“澜湄周”活动在北京举行。水利部国科司、外交部亚洲司和边海司、湄公河五国驻华使馆以及澜湄水资源合作单位的代表嘉宾出席活动。北京国信华源公司特邀参加&#xff0c;现场就深化澜湄水资源合作展开深入交流研讨。 澜湄六国&#xff0c;…

2022-2003年上市公司企业商业信用融资数据

01、数据简介 企业商业信用融资是指企业之间在买卖商品时&#xff0c;以商品形式提供的借贷活动。这种融资方式是经济活动中一种最普遍的债权债务关系。商业信用的存在对于扩大生产和促进流通起到了十分积极的作用&#xff0c;但不可避免的也存在着一些消极的影响。 测算方式…

使用 LooperPrinter 监控 Android 应用的卡顿

在 Android 开发中&#xff0c;主线程&#xff08;UI线程&#xff09;的卡顿直接影响用户体验。LooperPrinter 是一种有效的工具&#xff0c;可以帮助我们监测和识别这些卡顿。下面是如何实现 LooperPrinter 监控的详细步骤和相应的 Kotlin 代码示例。 步骤 1: 创建自定义的 P…

牛客JZ47 礼物的最大价值【中等 动态规划 C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/2237b401eb9347d282310fc1c3adb134 思路 动态规划&#xff1a; 每个单元格依赖于他的上边a和左边b&#xff0c;单元格的值为max(a,b)自己的值参考答案C class Solution {public:/*** 代码中的类名、方法名、参…

京东web京东,m端滑块,h5st4.2,4.3,4.7

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章未…

力扣33. 搜索旋转排序数组

Problem: 33. 搜索旋转排序数组 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化左右指针&#xff1a;首先&#xff0c;定义两个指针left和right&#xff0c;分别指向数组的开始和结束位置。 2.计算中间值&#xff1a;在left和right之间找到中间位置mid。 3.比较中间值…

strstr,strnstr函数详解

strstr函数 strstr函数是C语言中的一个字符串函数&#xff0c;用于在一个字符串中查找另一个字符串的出现位置。 它的函数原型如下&#xff1a; char *strstr(const char *haystack, const char *needle); 在这个函数中&#xff0c;haystack表示被搜索的字符串&#xff0c;…

【多态】有关多继承和菱形继承的多态

博主首页&#xff1a; 有趣的中国人 专栏首页&#xff1a; C进阶 其它专栏&#xff1a; C初阶 | 初阶数据结构 | Linux 博主会持续更新 本篇文章主要讲解 多继承和菱形继承的多态 的相关内容 文章目录 1. 回顾多态底层2. 抽象类2.1 概念2.2 接口继承和实现继承 3. 虚表所在…

Linux——web建立wordpress

下载 [rootnfs-server ~]# yum install php wget https://wordpress.org/latest.tar.gz解压 /var/www/html [rootnfs-server html]# tar -xzvf latest.tar.gz [rootnfs-server html]# rm latest.tar.gz授权 [rootnfs-server html]# chown -R www:www /var/www/html添加文件备…

利用kimi等大模型进行运维参数解析和调优

在运维时&#xff0c;经常遇到很多参数&#xff0c;有些参数不知道意义&#xff0c;知道意义的也有些不知道合理参考值是多少。利用kimi等大模型来当老司机&#xff0c;轻松解决运维难题。 例如在运维hive参数时&#xff0c;有些不知道作用&#xff0c;提示次如下 你的角色是…

windows ubuntu sed,awk,grep篇:7.sed 多行模式及循环

目录 46.读取下一行数据并附加到模式空间(命令 N) 47.打印多行模式中的第一行(命令 P) 48. 删除多行模式中的第一行(命令 D) 49.循环和分支(命令 b 和 :label 标签) 50.使用命令 t 进行循环 Sed 默认每次只处理一行数据&#xff0c;除非使用 H,G 或者 N 等命令创建多行模式&…

python学习笔记B-11:序列结构之列表--二维列表的遍历和生成式

二维列表的遍历方式&#xff0c;使用双层for循环&#xff0c;遍历索引号。 二维列表的生成式&#xff0c;也是使用类似双层循环的形式生成。 print("##初始化二维列表&#xff0c;每个元素就是1个列表") lst [["东方延续","太空军自然选择号舰长&qu…

释放Stable Diffusion 无限可能

最近在整理大语言模型的系列内容&#xff0c;Stable Diffusion 是我下一篇博客的主题。关注 Stable Diffusion&#xff0c;是因为它是目前最受欢迎和影响力最大的多模态生成模型之一。Stable Diffusion 于 2022 年 8 月发布&#xff0c;主要用于根据文本的描述产生详细图像&…

基于SpringBoot+Vue笔记记录分享网站设计与实现

项目介绍&#xff1a; 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代…

C语言 | Leetcode C语言题解之第50题Pow(x,n)

题目&#xff1a; 题解&#xff1a; double myPow(double x, int n){if(n 0 || x 1){return 1;}if(n < 0){return 1/(x*myPow(x,-(n1)));}if(n % 2 0){return myPow(x*x,n/2);}else{return x*myPow(x*x,(n - 1)/2);} }

【Jenkins】持续集成与交付 (三):有关报错解决(Jenkins (2.387.3) or higher required)

🟣【Jenkins】持续集成与交付 (三):有关报错解决Jenkins (2.387.3) or higher required 一、Jenkins主页报错二、安装Jenkins插件报错三、解决过程(解压替换jenkins.war)四、重新访问登录💖The Begin💖点点关注,收藏不迷路💖 一、Jenkins主页报错 New version …

吴恩达2022机器学习专项课程(一)7.2 逻辑回归的简化成本函数

问题预览/关键词 本节课内容逻辑回归的损失函数简化之后的形式是&#xff1f;为什么可以简化&#xff1f;成本函数的通用形式是&#xff1f;逻辑回归成本函数的最终形式是&#xff1f;逻辑回归为什么用对数损失函数计算成本函数&#xff1f;为什么不直接给出逻辑回归损失函数的…