单源最短路径 洛谷【P4779】

news2024/9/16 6:19:33

题目描述

给定一个 nn 个点,mm 条有向边的带非负权图,请你计算从 ss 出发,到每个点的距离。

数据保证你能从 ss 出发到任意点。

输入格式

第一行为三个正整数 n,m,sn,m,s。 第二行起 mm 行,每行三个非负整数 ui,vi,wiui​,vi​,wi​,表示从 uiui​ 到 vivi​ 有一条权值为 wiwi​ 的有向边。

输出格式

输出一行 nn 个空格分隔的非负整数,表示 ss 到每个点的距离。

输入输出样例

输入 #1

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出 #1

0 2 4 3

说明/提示

样例解释请参考 数据随机的模板题。

1≤n≤1051≤n≤105;

1≤m≤2×1051≤m≤2×105;

s=1s=1;

1≤ui,vi≤n1≤ui​,vi​≤n;

0≤wi≤1090≤wi​≤109, 

0≤∑wi≤1090≤∑wi​≤109。

代码解答: 

cpp
#include <iostream>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <limits>

using namespace std;

// 常量定义
const int INF = numeric_limits<int>::max();
const int MAX_NODES = 100010;    // 最大节点数
const int MAX_EDGES = 500010;    // 最大边数

// 边的结构体
struct Edge {
    int destination, weight, next; // 目的节点、边的权重、下一条边的索引
};

// 邻接表
Edge edges[MAX_EDGES];
int head[MAX_NODES], edgeCount = 0; // head 数组表示每个节点的邻接边链表,edgeCount 记录总边数

// 向邻接表中添加一条边
void addEdge(int from, int to, int weight) {
    edges[++edgeCount].destination = to;
    edges[edgeCount].weight = weight;
    edges[edgeCount].next = head[from];
    head[from] = edgeCount;
}

int numNodes, numEdges, source;
int distances[MAX_NODES]; // 保存从源点到每个节点的最短距离

// 节点结构体,用于优先队列中的元素
struct Node {
    int id, distance;
    bool operator < (const Node &other) const {
        return distance > other.distance; // 小顶堆(距离小的优先)
    }
};

// Dijkstra 算法
void dijkstra() {
    fill(distances, distances + numNodes + 1, INF); // 初始化所有距离为 INF
    distances[source] = 0; // 源点到自己的距离为 0
    priority_queue<Node> pq; // 优先队列(最小堆)
    pq.push({source, 0});
    
    while (!pq.empty()) {
        Node current = pq.top();
        pq.pop();
        int u = current.id;
        int currentDistance = current.distance;
        
        if (currentDistance != distances[u]) continue; // 如果当前距离已经不是最短距离,则跳过
        
        // 遍历所有邻接边
        for (int i = head[u]; i; i = edges[i].next) {
            int v = edges[i].destination;
            int weight = edges[i].weight;
            
            // 如果通过 u 到达 v 的距离更短,则更新并加入优先队列
            if (distances[u] + weight < distances[v]) {
                distances[v] = distances[u] + weight;
                pq.push({v, distances[v]});
            }
        }
    }
}

int main() {
    int from, to, weight;
    scanf("%d%d%d", &numNodes, &numEdges, &source); // 读取节点数、边数和源点
    for (int i = 1; i <= numEdges; i++) {
        scanf("%d%d%d", &from, &to, &weight); // 读取每条边的信息
        addEdge(from, to, weight);
    }
    
    dijkstra(); // 执行 Dijkstra 算法
    
    for (int i = 1; i <= numNodes; i++) {
        if (distances[i] == INF) {
            printf("INF ");
        } else {
            printf("%d ", distances[i]);
        }
    }
    
    return 0;
}

局部代码解析: 

 const int INF = numeric_limits<int>::max():

在 C++ 中,const int INF = numeric_limits<int>::max(); 是用来定义一个表示“无穷大”的常量。这个常量通常用于图算法中,作为一种便捷的方式来表示一个节点到其他节点的距离是不可达的。下面是详细的解释:

numeric_limits<int>::max()

  • numeric_limits<int> 是 C++ 标准库中的一个模板类,用于提供有关 int 类型的信息。
  • max() 是 numeric_limits 类的一个静态成员函数,它返回该类型可以表示的最大值。

例如,对于 int 类型,numeric_limits<int>::max() 通常返回 2147483647(在大多数系统上),这表示 int 类型能够存储的最大整数值。

 

bool operator < (const Node &other) const:

在 C++ 中,operator< 的重载用于定义两个对象在特定条件下的大小关系。对于 Node 结构体,重载 < 运算符通常是为了在容器中如优先队列(std::priority_queue)或者集合(std::set)中确定元素的排序方式。

让我们详细分析 bool operator < (const Node &other) const 的重载在 Node 结构体中的用途:

cpp
struct Node {
    int id, distance;

    bool operator < (const Node &other) const {
        return distance > other.distance; // 实现小顶堆的排序
    }
};
 作用
  1. 定义排序规则

    • 这个重载的 < 运算符定义了两个 Node 对象的比较方式。特别地,这个实现会影响数据结构如何对这些 Node 对象进行排序。
    • 在标准的 std::priority_queue 中,元素是根据优先级(或排序标准)进行排列的。默认情况下,std::priority_queue 实现为大顶堆(即最大优先队列),即最大元素优先出队列。
  2. 小顶堆实现

    • 在 Node 结构体中,bool operator < (const Node &other) const { return distance > other.distance; } 实现了一个小顶堆(即最小优先队列)的排序规则。
    • 具体来说,这行代码表示如果当前 Node 的 distance 大于 other 的 distance,那么当前 Node 被认为不小于 other。因此,具有较小 distance 的 Node 会有更高的优先级,被优先处理。
为什么要这么写?
  • 优先队列的要求

    • std::priority_queue 默认是大顶堆。如果希望实现小顶堆,可以通过重载 < 运算符来改变排序规则。这是因为 std::priority_queue 是基于堆实现的,其中堆的性质是通过比较操作定义的。
  • 小顶堆的实现

    • 小顶堆中的根节点是所有节点中 distance 最小的节点。为了让小顶堆的性质成立,较小的 distance 应该排在前面(即更高的优先级)。因此,通过将 distance > other.distance 用于比较,确保了距离较小的节点会优先于距离较大的节点。

实际应用

在实际应用中,例如 Dijkstra 算法中使用优先队列来处理图的节点时,节点的距离是算法的关键部分。通过使用小顶堆,可以确保每次从队列中取出的节点都是当前距离最小的节点,这样算法能正确地找到最短路径。

 

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

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

相关文章

oracle数据库安装和配置

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; Oracle 数据库的安装和配置是一个较为复杂的过程&#xff0c;涉及多个步骤和配置项。以下将详细介绍如何在 Linux 和 Windows 系统中安装 Oracle 数据库并进行基础配置。 一、Oracle 数据库安装前的准备 …

结账打印--SAAS本地化及未来之窗行业应用跨平台架构

一代码 var 打印数据 {shopname:"广发系统"};var 打印渲染2 打印模板.解析(打印模板,打印数据x,"wlzc");console.log("未来之城");console.log(打印渲染2);var 对话框_打印_id "多大啥事";var 对话框_打印_内容 未来之窗_打印数据渲…

ICM20948 DMP代码详解(6)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;5&#xff09; 前一篇文章解析了EMP-App中的入口函数main()中重点关注的第1段代码&#xff0c;本回继续往下进行解析。为了便于理解和回顾&#xff0c;再次贴出main函数源码&#xff1a; int main (void) {int rc 0…

一次关于生产环境服务无故宕机的排查过程

故事的开始 这个故事是在一年之前&#xff0c;当时我们的系统运行在客户的k8s环境上。然后很神奇的是每个月底我们都会服务宕机&#xff0c;当然我们开启了多个实例。当时的容器线条就像心跳图一样&#xff08;或许有些描述的不太准确&#xff0c;我没有找到当时那个像心电图一…

【Map】、集合总结

Map(*)——映射 比较之前的集合 List 为什么使用map <k,v>&#xff1a;key–value Api–>尽量用k去操作value put<k,v> package com.ffyc.map;import java.util.HashMap; import java.util.Map;/*** 映射*/ public class MapDemo {public static void main(St…

Linux下的Makefile与进度条程序

目录 Linux下的Makefile与进度条程序 Makefile与make Makefile与make介绍 创建第一个Makefile并使用make Makefile文件基本格式介绍 Makefile依赖方法执行过程 Makefile通用写法 进度条程序 实现效果 前置知识 回车(\r)与换行(\n) 输出缓冲区 实现进度条 Linux下的…

vue+ThreeJS:从0 到1 搭建开发环境

文章目录 一、下载安装&#xff08;懒人版&#xff09;二、顺序安装1&#xff0c;下载安装nodejs2&#xff0c;安装vue-cli3&#xff0c;创建vue-three 项目。4&#xff0c;安装threeJS5&#xff0c;安装element UI &#xff08;选装&#xff09;最终package.json文件如下&…

C语言深入理解指针3

1.字符指针变量 在指针类型中char*是字符指针 int main() {char ch w;char* pc &ch;//pc是字符指针变量//字符指针变量是用来存放地址的const char* p "abcsefghi";// 不是将abcdefghi\0存放到p中// 而是将首字符a的地址存放在p中// "abcsefghi"是…

逻辑代数的基本规则

目录 逻辑代数的基本规则 带入规则 反演规则 对偶规则 逻辑代数的基本规则 带入规则 将逻辑等式两边的某一变量均用同一个逻辑函数代替&#xff0c;等式仍然成立。 可以用A非代替A&#xff0c;也可以用C代替B。 也可使用BC这样一个整体代替B。 反演规则 可以把与换或&#x…

营养作用的对象是有区别的 第八篇

除了7大营养素 还需要补充其他营养素 食品营养学 临床营养学 大众营养学 食品营养学 你要早点就开始预防

怎么强制撤销excel工作表保护?

经常不是用的Excel文件设置了工作表保护&#xff0c;偶尔打开文件的时候想要编辑文件&#xff0c;但是发现忘记了密码&#xff0c;那么这种情况&#xff0c;我们怎么强制撤销excel工作表保护&#xff1f;今天分享两种解决方法。 方法一、 将excel文件转换为其他文件格式&…

C语言进阶【1】--字符函数和字符串函数【1】

本章概述 字符分类函数字符转换函数strlen的使用和模拟实现strcpy的使用和模拟实现strcat的使用和模拟实现strcmp的使用和模拟实现彩蛋时刻&#xff01;&#xff01;&#xff01; 字符分类函数 字符&#xff1a; 这个概念&#xff0c;我们在以前的文章中讲过了。我们键盘输入的…

通信工程学习:什么是MPC多媒体个人计算机、MCS多媒体计算机系统

一、MPC多媒体个人计算机&#xff08;Multimedia Personal Computer&#xff09; 1、MPC多媒体个人计算机定义 多媒体个人计算机&#xff08;MPC&#xff09;是指具备处理多媒体信息&#xff08;如音频、视频、图像、动画和文本等&#xff09;能力的个人计算机。它不仅具备传统…

html记账本改写:保存数据 localStorage。

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>记账本改写</title><style>table {user-select: none;/* width: 100%; */border-collapse: collapse;}table,th,td {border: 1px solid…

数据集 3DPW-开源户外三维人体建模-姿态估计-人体关键点-人体mesh建模 >> DataBall

3DPW 3DPW-开源户外三维人体建模数据集-姿态估计-人体关键点-人体mesh建模 开源户外三维人体数据集 inproceedings{vonMarcard2018, title {Recovering Accurate 3D Human Pose in The Wild Using IMUs and a Moving Camera}, author {von Marcard, Timo and Henschel, Robe…

从“游戏科学”到玄机科技:《黑神话:悟空》的视角打开动漫宇宙

近日&#xff0c;中国游戏界迎来了一场前所未有的盛事——由游戏科学公司开发的《黑神话&#xff1a;悟空》正式上线&#xff0c;并迅速成为全球玩家热议的焦点。在居高不下的讨论热度中&#xff0c;有人说他的成功在于对《西游记》为背景进行改编&#xff0c;对原著进行了分析…

读软件设计的要素04概念的关系

1. 概念的关系 1.1. 概念是独立的&#xff0c;彼此间无须相互依赖 1.1.1. 一个概念是应该独立地被理解、设计和实现的 1.1.2. 独立性是概念的简单性和可重用性的关键 1.2. 软件存在依赖性 1.2.1. 不是说一个概念需要依赖另一个概念才能正确运行 1.2.2. 只有当一个概念存在…

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 示例 1&#xff1a; 输入:a "11", b "1" 输出&#xff1a;"100" 示例 2&#xff1a; 输入&#xff1a;a "1010", b "…

单GPU一分钟生成16K高清图像!新加坡国立发布LinFusion:无缝兼容Stable Diffusion插件

论文链接&#xff1a;https://arxiv.org/pdf/2409.02097 Git链接&#xff1a;https://lv-linfusion.github.io/ 亮点直击 本文研究了Mamba的非因果和归一化感知版本&#xff0c;并提出了一种新颖的线性注意力机制&#xff0c;解决了扩散模型在高分辨率视觉生成中的挑战。 本文…

Vue——day11之生命周期

目录 生命周期的八个阶段 生命周期执行的流程图 代码示例 总结 Vue的生命周期是指在Vue实例创建、挂载、更新和销毁过程中&#xff0c;会触发的一系列钩子函数。这些钩子函数可以用来在不同的生命周期阶段执行相应的逻辑操作。 生命周期的八个阶段 Vue的生命周期可以分为…