每周一算法:多起点最短路

题目描述

有一天,琪琪想乘坐公交车去拜访她的一位朋友。由于琪琪非常容易晕车,所以她想尽快到达朋友家。

现在给定你一张城市交通路线图,上面包含城市的公交站台以及公交线路的具体分布。

已知城市中共包含 n n n个车站(编号 1 ∼ n 1\sim n 1n),以及 m m m 条公交线路。

每条公交线路都是单向的,从一个车站出发直接到达另一个车站,两个车站之间可能存在多条公交线路。

琪琪的朋友住在 s s s号车站附近。琪琪可以在任何车站选择换乘其它公共汽车。

请找出琪琪到达她的朋友家(附近的公交车站)需要花费的最少时间。

输入格式

输入包含多组测试数据。

每组测试数据第一行包含三个整数 n , m , s n,m,s n,m,s,分别表示车站数量,公交线路数量以及朋友家附近车站的编号。

接下来 m m m 行,每行包含三个整数 p , q , t p,q,t p,q,t,表示存在一条线路从车站 p p p 到达车站 q q q,用时为 t t t

接下来一行,包含一个整数 w w w,表示琪琪家附近共有 w w w 个车站,她可以在这 w w w 个车站中选择一个车站作为始发站。

再一行,包含 w w w 个整数,表示琪琪家附近的 w w w 个车站的编号。

输出格式

每个测试数据输出一个整数作为结果,表示所需花费的最少时间。

如果无法达到朋友家的车站,则输出 -1

每个结果占一行。

样例 #1

样例输入 #1

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

样例输出 #1

1
-1

提示

【数据范围】

n ≤ 1000 , m ≤ 20000 n≤1000,m≤20000 n1000,m20000,
1 ≤ s ≤ n 1≤s≤n 1sn,
0 < w < n 0<w<n 0<w<n,
0 < t ≤ 1000 0<t≤1000 0<t1000

算法思想一:反向建边

根据题目描述,琪琪家附近共有 w w w 个车站,可以在任何车站选择换乘其它公共汽车,目标是到达 s s s号车站附近的朋友家。也就是说起点可以有多个,终点只有 1 1 1个,求从多个起点出发到达终点的最短路。

基于上述分析,可以反向建边,利用单源最短路算法,例如「Dijkstra」或者「SPFA」,求终点到所有起点的最短路,然后打擂台求一个最小值即可。

时间复杂度

这里使用「SPFA」求最短路,其平均时间复杂度为 O ( k n ) O(kn) O(kn) k k k是一个很小的常数,最坏情况下是 O ( n m ) O(nm) O(nm);一共有 T T T组测试样例,因此总的时间复杂度为 O ( T × k n ) O(T\times kn) O(T×kn)

代码实现

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 20005, INF = 0x3f3f3f3f; 
int h[N], e[M], w[M], ne[M], idx;
int n, m, s, t, p[N], dis[N], q[N], st[N];
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void spfa()
{
    memset(dis, 0x3f, sizeof dis);
    int hh = 0, tt = 0;
    dis[s] = 0; st[s] = 1; q[tt ++] = s;
    while(hh != tt) //循环队列
    {
        int u = q[hh ++];
        if(hh == N) hh = 0; //循环队列
        st[u] = 0;
        for(int i = h[u]; ~ i; i = ne[i])
        {
            int v = e[i];
            if(dis[v] > dis[u] + w[i])
            {
                dis[v] = dis[u] + w[i];
                if(!st[v])
                {
                    st[v] = 1; q[tt ++] = v;
                    if(tt == N) tt = 0; //循环队列
                }
            }
        }
    }
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &s) != -1)
    {
        memset(h, -1, sizeof h);
        idx = 0; //多组测试样例,需要重置idx
        for(int i = 0; i < m; i ++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(b, a, c); //反向建边
        }
        scanf("%d", &t);
        for(int i = 0; i < t; i ++) scanf("%d", &p[i]);
        spfa();
        int ans = INF;
        for(int i = 0; i < t; i ++) ans = min(ans, dis[p[i]]);
        if(ans == INF) puts("-1");
        else printf("%d\n", ans);
    }    
    return 0;
}

算法思想二:虚拟源点

反向建边的思想可以解决从多个起点出发到达终点的最短路问题,但是当终点也有多个时,则无法处理。此时,除了「Floyd」算法之外,还可以使用虚拟源点的思想来处理。

基本思想就是设置一个虚拟源点从该源点到每个起点建立一条权重为0的边。如下图所示:
在这里插入图片描述
这样,对于每条从起点到终点的最短路,都可以对应一条从虚拟源点出发,经过起点到达终点的最短路。这样就可以利用单源最短路算法,例如「Dijkstra」或者「SPFA」,直接求虚拟源点到终点的最短路即可。

代码实现

#include <bits/stdc++.h>
using namespace std;
//注意,由于引入了虚拟节点,边数要相应增加
const int N = 1005, M = 21005, INF = 0x3f3f3f3f; 
int h[N], e[M], w[M], ne[M], idx;
int n, m, s, t, q[N], dis[N], st[N];
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

int spfa()
{
    memset(dis, 0x3f, sizeof dis);
    int hh = 0, tt = 0;
    dis[0] = 0; st[0] = 1; q[tt ++] = 0; //将虚拟源点0加入队列
    while(hh != tt) //循环队列
    {
        int u = q[hh ++];
        if(hh == N) hh = 0; //循环队列
        st[u] = 0;
        for(int i = h[u]; ~ i; i = ne[i])
        {
            int v = e[i];
            if(dis[v] > dis[u] + w[i])
            {
                dis[v] = dis[u] + w[i];
                if(!st[v])
                {
                    st[v] = 1; q[tt ++] = v;
                    if(tt == N) tt = 0; //循环队列
                }
            }
        }
    }
    if(dis[s] == INF) return -1;
    else return dis[s];
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &s) != -1)
    {
        memset(h, -1, sizeof h);
        idx = 0; //多组测试样例,需要重置idx
        for(int i = 0; i < m; i ++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c); //正向建边
        }
        scanf("%d", &t); //输入起点个数
        for(int i = 0; i < t; i ++) 
        {
            int s;
            scanf("%d", &s);
            add(0, s, 0); //从虚拟源点0建一条权重为0、指向起点s的边
        }
        printf("%d\n", spfa());
    }
    
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Adobe Firefly Image 3:创新步伐与挑战并存的AI图像生成技术升级

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

编写你的第一个java 程序

1.安装 jdk 网址&#xff1a; Java Downloads | Oracle 一般我们安装jdk 17 就行了 自己练习 自己学习 真正的开发中我们使用jdk 8 这个是最适合开发java 应用程序的 当然你也可以选择你的 系统 来安装这个java 在文件资源管理器打开JDK的安装目录的bin目录&#xff0c;会发…

VSCode通过跳板机免密连接远程服务器的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Android Monkey工具介绍与使用

过于爽快的承认失败&#xff0c;就可能发觉不了曾经与正确非常接近。大家好&#xff0c;依旧是在翻看旧文档的时候&#xff0c;发现一篇关于Monkey的介绍和使用&#xff0c;Monkey这款工具在软件测试中主要用于进行压力测试和稳定性测试。它可以模拟大量随机的用户操作&#xf…

618买什么最划算?618买什么东西便宜?必备数码好物清单分享

​只不&#xff0c;马上又到了618购物节咯&#xff0c;数码产品的优惠力度尤为显著&#xff0c;是购买数码产品的绝佳时机。接下来&#xff0c;我将为大家分享几款性价比超高的数码产品&#xff0c;相信总有一款能吸引你的目光。 一、南卡OE MIX开放式蓝牙耳机 在618购物狂欢节…

javaScript中的闭包

什么是闭包 在理解 JavaScript 中的闭包前先了解以下两个知识点&#xff1a; JavaScript 中的作用域和作用域链JavaScript 中的垃圾回收 简单回顾一下这两个知识点&#xff1a; 1. JavaScript 中的作用域和作用域链 作用域就是一个独立的地盘&#xff0c;让变量不会外泄、…

tomcat 配置支持 ssl 附效果图

1、修改tomcat配置文件server.xml: vim ./conf/server.xml 把配置文件&#xff1a; <Connector port"8088" Server" " protocol"HTTP/1.1"connectionTimeout"20000"redirectPort"8443" URIEncoding"UTF-8" …

C++ | Leetcode C++题解之第46题全排列

题目&#xff1a; 题解&#xff1a; class Solution { public:void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){// 所有数都填完了if (first len) {res.emplace_back(output);return;}for (int i first; i &…

逆数对(树状数组的方法)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 5 4 5 1 3 2 输出 7 思路&#xff1a; 根据题意&#xff0c;求逆序对总数。 逆序对含义&#xff1a;如果数组中的两个不同位置&#xff0c;前面的数字比后面的数字严格大&…

投票刷礼物链接怎么弄?最新投票活动创建系统源码 轻松创建活动

投票刷礼物链接怎么弄&#xff1f;投票活动创建系统的作用和功能多种多样&#xff0c;为用户提供一个便捷、高效且功能强大的平台&#xff0c;用于创建、管理和执行各种投票活动。分享一个最新投票活动创建系统源码&#xff0c;源码开源可二开&#xff0c;含完整代码包和详细搭…

SCA-CNN-LSTM多输入回归预测|正余弦优化算法-卷积-长短期神经网络|Matlab

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

[笔试训练](五)

013 游游的you__牛客网 (nowcoder.com) 题目&#xff1a; 题解&#xff1a; 组成一个you需要一个o且能得2分&#xff0c;而组成相邻字母oo需要两个o&#xff0c;只能得1分。优先考虑组成尽可能多的you&#xff0c;再考虑剩下的o&#xff0c;放一起。 #include <iostream…

【C++】C++的四种类型转换

一、C语言中的类型转换 在C语言中有两种类型转换&#xff0c;隐式类型转换和显示类型转换。 如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与接收返回值类型不一致时&#xff0c;就需要发生类型转化。 隐式类型转换&#…

汽车IVI中控开发入门及进阶(十六):carplay认证

现在有些中控采用高通的芯片如8155、8295等,实现多屏互动等,但是也有一些车型走低成本方案,比如能够实现HiCar、CarLife或者苹果Apple的Carplay等能进行手机投屏就好了。 能实现CarPlay功能通过Carplay认证,也就成了一些必须的过程,国产车规级中控芯片里,开阳有一款ARK1…

Android SDK Manager安装Google Play Intel x86 Atom_64 System Image依赖问题

Package Google Play Intel x86 Atom_64 System Image,Android API R, revision 2 depends on SDK Platform Android R Preview, revision 2 问题 一开始以为网络还有依赖包没有勾选&#xff0c;尝试了很多次&#xff0c;勾选这边报错对应的license即可。此时点击一下其他licen…

深入探索Go语言:io库的实战应用全解析

深入探索Go语言&#xff1a;io库的实战应用全解析 引言io库概览Reader接口Writer接口Closer接口Seeker接口 文件操作打开和关闭文件读取文件写入文件错误处理 数据读写技巧使用缓冲读写缓冲读取缓冲写入 复用缓冲区提高读写效率的技巧 处理I/O流网络I/O的处理创建简单的HTTP服务…

cdo 修改 calendar 为标准的格式

使用ncl脚本时出现警告&#xff1a;day_of_year: illegal calendar proleptic_gregorian 其原因是读取的降水nc文件是我手动合并生成&#xff0c;所以时间的calendar不是很标准&#xff0c;数据信息如下所示&#xff0c;可以发现Calendar是proleptic_gregorian&#xff0c;这…

前端补充17(JS)

一、JS组成成分 JS的组成成分&#xff0c;由三部分组成 第一、ECMAScript&#xff1a;语法规则&#xff0c;如何定义变量&#xff0c;数据类型有哪些&#xff0c;如何转换数据类型&#xff0c;if判断 if-else while for for-in forEach do-while switch 数组 函数 对…

Python小功能实现(链接下载图品并存储到EXCEL中)

import os import requests from openpyxl import Workbook from openpyxl.drawing.image import Image from concurrent.futures import ThreadPoolExecutor# 图片链接列表 image_urls ["https://uploads/file/20230205/f85Lpcv8PXrLAdmNUDE1Hh6xqkp0NHi2gSXeqyOb.png&q…

3月魅力彩妆行业数据分析:某国产品牌彩妆产品销额将近30亿!

彩妆行业发展多年&#xff0c;经历了多重红利期和激烈的市场竞争后&#xff0c;进入到缓慢发展时期。 根据鲸参谋数据显示&#xff0c;今年3月在线上电商平台&#xff08;淘宝天猫京东&#xff09;彩妆产品销量累计超过6700万件&#xff0c;同比去年下降了29%&#xff1b;销售…
最新文章