【每周题解】道路与航线

题目描述

农夫约翰正在一个新的销售区域对他的牛奶销售方案进行调查。他想把牛奶送到 T T T 个城镇,编号为 1 ∼ T 1\sim T 1T

这些城镇之间通过 R R R 条道路 (编号为 1 1 1 R R R) 和 P P P 条航线 (编号为 1 1 1 P P P) 连接。

每条道路 i i i 或者航线 i i i 连接城镇 A i A_i Ai B i B_i Bi,花费为 C i C_i Ci

对于道路, 0 ≤ C i ≤ 10 , 000 0≤C_i≤10,000 0Ci10,000;然而航线的花费很神奇,花费 C i C_i Ci 可能是负数( − 10 , 000 ≤ C i ≤ 10 , 000 −10,000≤C_i≤10,000 10,000Ci10,000)。

道路是双向的,可以从 A i A_i Ai B i B_i Bi,也可以从 B i B_i Bi A i A_i Ai,花费都是 C i C_i Ci

然而航线与之不同,只可以从 A i A_i Ai B i B_i Bi

事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策:保证如果有一条航线可以从 A i A_i Ai B i B_i Bi,那么保证不可能通过一些道路和航线从 B i B_i Bi 回到 A i A_i Ai

由于约翰的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。

他想找到从发送中心城镇 S S S 把奶牛送到每个城镇的最便宜的方案。

输入格式

第一行包含四个整数 T , R , P , S T,R,P,S T,R,P,S

接下来 R R R 行,每行包含三个整数(表示一个道路) A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci

接下来 P P P 行,每行包含三个整数(表示一条航线) A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci

输出格式

1.. T 1..T 1..T 行:第 i i i 行输出从 S S S 到达城镇 i i i 的最小花费,如果不存在,则输出 NO PATH

样例 #1

样例输入 #1

6 3 3 4
1 2 5
3 4 5
5 6 10
3 5 -100
4 6 -100
1 3 -10

样例输出 #1

NO PATH
NO PATH
5
0
-95
-100

提示

【数据范围】
1 ≤ T ≤ 25000 1≤T≤25000 1T25000,
1 ≤ R , P ≤ 50000 1≤R,P≤50000 1R,P50000,
1 ≤ A i , B i , S ≤ T 1≤A_i,B_i,S≤T 1Ai,Bi,ST

算法思想

根据题目描述:

  1. 道路是双向的,可以从A到B,也可以从B到A,花费都是C;而航线是单向的,只可以从A到B
  2. 题目中保证如果有一条航线可以从A到B,那么保证不可能通过一些道路和航线从B回到A
  3. 题目要求的就是起点到各个点的最短距离之和

显然是求单源最短路问题,但图中带有负权边,不能直接使用Dijkstra算法。考虑题目中给出的性质,双向边都是非负的,只有单向边可能是负的,并且单向边不构成环。

如果只把双向边添加到图中,那么会形成若干个连通块,可以把每个连通块看作一个点,再把单向边添加到图中,会得到一张有向无环图。在有向无环图中,无论边权正负,都可以按照拓扑序进行遍历,在线性时间复杂度内求出单源最短路。

算法流程

  • 只把双向边加入图中,用深度优先遍历划分图中的连通块,记 c [ u ] c[u] c[u]为节点 u u u所属连通块的编号。
  • 统计每个连通块的总入度,即 d [ i ] d[i] d[i]为第 i i i个连通块的总入度
  • 建立一个队列,存储连通块的编号,用于拓扑排序。最初队列中包含所有入度为 0 0 0的连通块编号。设 d i s [ S ] = 0 dis[S]=0 dis[S]=0表示起点到自己的距离为0,其余点的初始化为无穷大。
  • 取出队头的连通块 i i i,对该连通块执行堆优化的Dijkstra算法,重复该步骤直至队列为空:
    1. 建立一个堆,把第 i i i个连通块中所有节点加入堆中
    2. 从堆中取出 d i s [ u ] dis[u] dis[u]最小的节点 u u u
    3. u u u被扩展过,则回到步骤 2 2 2
    4. 遍历从 u u u出发的所有边 ( u , v , w ) (u, v, w) (u,v,w),用 d i s [ u ] + w dis[u]+w dis[u]+w更新 d i s [ v ] dis[v] dis[v]
    5. 如果 u u u v v v在同一个连通块中,即 c [ u ] = c [ v ] c[u]=c[v] c[u]=c[v],并且 d i s [ v ] dis[v] dis[v]被更新,则将 v v v插入堆中
    6. c [ u ] ≠ c [ v ] c[u]\ne c[v] c[u]=c[v],则令 d [ c [ v ] ] d[c[v]] d[c[v]]减去 1 1 1,如果减到 0 0 0,则将 c [ v ] c[v] c[v]插入拓扑排序的队列尾部。
    7. 重复 2 ∼ 6 2\sim6 26,直至堆为空

时间复杂度

整个算法的时间复杂度为 O ( T + P + R l o g T ) O(T+P+RlogT) O(T+P+RlogT)

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 25010, INF = 0x3f3f3f3f;
struct Edge
{
    int v, w;
};
vector<Edge> g[N];
int T, R, P, S, c[N], cnt, d[N], dis[N], st[N];
vector<int> b[N]; //存储每个连通块中的点
queue<int> q;
void dfs(int u, int k) //将与u连通的点加入第k个连通块
{
    c[u] = k; b[k].push_back(u); //将u加入k的连通块集合中
    for(Edge u : g[u])
    {
        int v = u.v;
        if(!c[v]) dfs(v, k);
    }
}
void dijkstra(int k)
{
    priority_queue<PII, vector<PII>, greater<PII>> h;
    //将连通块中所有点加入队列
    for(int u : b[k])
        h.push({dis[u], u});
    while(h.size())
    {
        PII t = h.top(); h.pop();
        int u = t.second;
        if(st[u]) continue;
        st[u] = 1;
        for(Edge e : g[u])
        {
            int v = e.v, w = e.w;
            //如果不在同一个连通块
            if(c[u] != c[v] && -- d[c[v]] == 0) q.push(c[v]);
            if(dis[v] > dis[u] + w) //能够缩短到v点的距离
            {
                dis[v] = dis[u] + w;
                if(c[u] == c[v]) //注意,如果u和v在同一个连通块,才加入堆中继续求最短距离
                    h.push({dis[v], v});
            }
        }
    }
}
void topsort()
{
    memset(dis, 0x3f, sizeof dis);
    dis[S] = 0;
    for(int i = 1; i <= cnt; i ++) //将入度为0的连通块加入拓扑排序的队列中
    {
        if(!d[i]) q.push(i);
    }
    
    while(q.size())
    {
        int k = q.front(); q.pop();
        dijkstra(k); //求连通块中的最短路
    }
}
int main()
{
    scanf("%d%d%d%d", &T, &R, &P, &S);
    for(int i = 1; i <= R; i ++)
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        g[u].push_back({v, w}), g[v].push_back({u, w});
    }
    for(int i = 1; i <= T; i ++) //处理连通块
         if(!c[i]) dfs(i, ++ cnt); //注意连通块的编号应从1开始
    
    for(int i = 1; i <= P; i ++)
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        g[u].push_back({v, w});
        d[c[v]] ++; //v所在的连通块的入度增加1
    }
    
    topsort(); //拓扑排序,按照拓扑序计算最短路
    
    for(int i = 1; i <= T; i ++)
        if(dis[i] > INF / 2) puts("NO PATH");
        else printf("%d\n", dis[i]);
}

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

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

相关文章

网络行为分析与异常检测

构建防火墙和使用简单的安全解决方案不足以保护网络免受网络异常或攻击&#xff0c;因为DDoS攻击、未知恶意软件和其他安全威胁一直在上升&#xff0c;改变了网络安全格局。网络管理员必须积极主动地分析网络&#xff0c;获得对网络的完全控制&#xff0c;并全面了解网络流量活…

C++ | Leetcode C++题解之第38题外观数列

题目&#xff1a; 题解&#xff1a; class Solution { public:string countAndSay(int n) {string prev "1";for (int i 2; i < n; i) {string curr "";int start 0;int pos 0;while (pos < prev.size()) {while (pos < prev.size() &&…

vue全屏后下拉框失效

如图&#xff0c;vue页面有个全屏功能 问题&#xff1a;全屏后下拉菜单消失 解决&#xff1a;加个这个 :teleported"false"如果不行试试这个 :popper-append-to-body"false"ok我话说完

nvidia-smi CUDA Version:N/A

问题 nvidia-smi显示&#xff1a;CUDA Version:N/A nvidia-smi -a显示&#xff1a;CUDA Version: Not Found 解决方法 查看Nvidia驱动版本 nvidia-smi如下图&#xff0c;版本为530.41.03 搜索cuda库 apt search libcuda注&#xff1a;不同的源&#xff0c;同一个库的命…

【大数据】bigtable,分布式数据库的鼻祖

目录 1.概述 2.数据模型 3.API 4.架构 5.一个完整的读写过程 6.如何查找到要的tablet 7.LSM树 1.概述 本文是作者阅读完bigtable论文后对bigtable进行的一个梳理&#xff0c;只涉及核心概念不涉及具体实操&#xff0c;具体实操会在后续的文章中推出。 GFS的出现虽然解…

海纳斯新装系统设置,安装删除卸载应用

文章目录 一、修改密码二、修改网卡地址三、修改主机名称四、挂载硬盘五、卸载应用省流版&#xff0c;直接执行以下脚本即可 六、安装网络流量可视化监控面板serverBee总结 一、修改密码 passwd root passwd ubuntu二、修改网卡地址 vi /etc/network/interfaces.d/eth0三、修…

HLS数据可以一起下载sentinel2源和Landsat89的数据吗?

可以的&#xff0c;地图资源工具可以同时下载同一时间段、同一范围的不同类别的数据&#xff0c;这对我们利用不同数据进行综合数据分析很有意义&#xff01;下面视频就是操作方法&#xff1a; 地图资源工具可以同时下载同一时间段、同一范围的不同类别的数据

人体行为识别/人体姿态估计AI算法模型介绍及场景应用

AI算法模型训练是指利用大量的数据以及特定的算法来训练出一个能够完成任务的计算模型。在进行AI算法模型训练时&#xff0c;通常需要经过以下几个步骤&#xff1a; 数据收集和预处理&#xff1a;首先需要收集用于训练的数据&#xff0c;然后对数据进行清洗、标注、归一化等处…

揭秘App广告变现,高效开发者必看攻略

在移动互联网高速发展的今天&#xff0c;应用市场竞争日益激烈。如何有效地进行app广告变现&#xff0c;是每个移动应用开发者都需要面对的挑战。以下是一些有效的广告变现策略。 选择合适的广告形式至关重要。插屏广告、横幅广告、视频广告等各有优劣&#xff0c;开发者需要根…

SQL注入作业

目录 一、万能密码和二阶注入测试 1.万能密码 2.二阶注入测试 二、联合查询注入测试 1.判断注入点 2.判断当前查询语句的列数 3.查询数据库基本信息 4.查询数据库中的数据 三、报错注入 1. 报错注入函数EXTRATVALUE 2.UPDATEXML 四、盲注测试 1.布尔盲注 判断数据…

16.4 冒泡排序

题目简介 排序动画模拟网站 phttps://www.cs.usfca.edugalles/visualization/ComparisonSort.htm 简洁版 #include <stdio.h> int main() {int a[10]{9,3,6,5,8,2,4,1,7,0};int n sizeof(a)/sizeof(int);int temp 0;for(int j0;j<n-1;j){ //外层循环循环9轮即可f…

Scala 第一篇 基础篇

Scala 第一篇 基础篇 一、变量与常量 1、变量2、常量 二、数据类型 1、数据基本类型概览2、元组的声明与使用3、Range介绍和使用4、Option 类型的使用和设计5、类型别名 三、运算符四、程序逻辑 1、一切都是表达式2、分支语句3、循环语句 五、集合 1、List2、Set3、Map4、Arra…

【大语言模型+Lora微调】10条对话微调Qwen-7B-Chat并进行推理 (聊天助手)

代码&#xff1a;https://github.com/QwenLM/Qwen/tree/main 国内源安装说明&#xff1a;https://modelscope.cn/models/qwen/Qwen-7B-Chat/summary 通义千问&#xff1a;https://tongyi.aliyun.com/qianwen 一、环境搭建 下载源码 git clone https://github.com/QwenLM/Qwen…

【python】如何通过python来发邮件,各种发邮件方式详细解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

27 管道

概念 管道式Unix中最古老的进程间通信的形式 把从一个进程连接到另一个进程的一个数据流称为一个“管道” 原理 task_struct中保存了一个files的结构体数组&#xff0c;里面存储了所有打开文件的编号&#xff0c;新打开一个文件&#xff0c;数据会写入到文件对应的 缓冲区中去…

程序,进程,进程管理的相关命令

程序 程序是执行特定任务的代码 1.是一组计算机能识别和执行的指令&#xff0c;运行于电子计算机上&#xff0c;满足人们某种需求的信息化工具 2.用于描述进程要完成的功能&#xff0c;是控制进程执行的指令集 进程的状态 为了对进程进行管理&#xff0c;操作系统首先定义…

上位机图像处理和嵌入式模块部署(树莓派4b实现xmlrpc通信)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面&#xff0c;我们也用纯API实现过上位机和开发板之间的通信。当时使用的方法&#xff0c;就是用windows自带的网络sdk和linux自带的api函数来完…

rc_visard 3D Stereo Senso

1 简介 rc_visard 3D立体视觉传感器 支持的接口标准 GenICam Generic Interface for CamerasGigE Gigabit Ethernet 词汇表 SGM semi-global matching 半全局匹配 SLAM Simultaneous Localization and Mapping 即时定位与地图构建 2 安全 3 硬件规格 坐标系 rc_visar…

linux信号相关概念

signal 信号引入什么是信号&#xff1f;如何产生信号&#xff1f;通过按键产生信号调用系统函数向进程发信号系统调用函数发送信号的流程: 由软件条件产生信号软件发送信号的流程&#xff1a; 硬件异常产生信号硬件异常的流程&#xff1a; Deliver、Pending、Block概念信号在内…

【Ne4j图数据库入门笔记1】图形数据建模初识

1.1 图形建模指南 图形数据建模是用户将任意域描述为节点的连接图以及与属性和标签关系的过程。Neo4j 图数据模型旨在以 Cypher 查询的形式回答问题&#xff0c;并通过组织图数据库的数据结构来解决业务和技术问题。 1.1.1 图形数据模型介绍 图形数据模型通常被称为对白板友…
最新文章