洛谷P3371题解

文章介绍了如何运用迪杰斯特拉算法解决一道关于求解有向图中单源最短路径的问题。题目要求从特定点出发,找到到达所有其他点的最短路径。文章提供了C++代码实现,包括初始化、核心逻辑和输出部分,强调了数据类型的选择和关键步骤的重要性。
摘要由CSDN通过智能技术生成

题外话

这是我的第一篇题解,请大家支持一下吧qwq ,如有错误欢迎各位大佬在评论区指正

正文

题面(洛谷P3371):传送门

【模板】单源最短路径(弱化版)

题目背景

本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步
P4779

题目描述

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。

输入格式

第一行包含三个整数 n , m , s n,m,s n,m,s,分别表示点的个数、有向边的个数、出发点的编号。

接下来 m m m 行每行包含三个整数 u , v , w u,v,w u,v,w,表示一条 u → v u \to v uv 的,长度为 w w w 的边。

输出格式

输出一行 n n n 个整数,第 i i i 个表示 s s s 到第 i i i 个点的最短路径,若不能到达则输出 2 31 − 1 2^{31}-1 2311

样例 #1

样例输入 #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

提示

【数据范围】 对于 20 % 20\% 20% 的数据: 1 ≤ n ≤ 5 1\le n \le 5 1n5 1 ≤ m ≤ 15 1\le m \le 15 1m15; 对于 40 % 40\% 40%
的数据: 1 ≤ n ≤ 100 1\le n \le 100 1n100 1 ≤ m ≤ 1 0 4 1\le m \le 10^4 1m104; 对于 70 % 70\% 70% 的数据: 1 ≤ n ≤ 1000 1\le n \le 1000 1n1000 1 ≤ m ≤ 1 0 5 1\le m \le 10^5 1m105; 对于 100 % 100\% 100% 的数据: 1 ≤ n ≤ 1 0 4 1 \le n \le 10^4 1n104 1 ≤ m ≤ 5 × 1 0 5 1\le m \le 5\times 10^5 1m5×105 1 ≤ u , v ≤ n 1\le u,v\le n 1u,vn w ≥ 0 w\ge 0 w0 ∑ w < 2 31 \sum w< 2^{31} w<231,保证数据随机。

Update 2022/07/29:两个点之间可能有多条边,敬请注意。

对于真正 100 % 100\% 100% 的数据,请移步
P4779。请注意,该题与本题数据范围略有不同。

样例说明:

图片1到3和1到4的文字位置调换

看到题面里的 w ≥ 0 w\ge 0 w0就知道这道题肯定要用迪杰斯特拉算法来做(另: 2 31 = 2147483647 2^{31}=2147483647 231=2147483647
首先定义一些东西:

#include <bits/stdc++.h>
using namespace std;
#define INF 2147483647
#define N 10005
int n, m, s;
long long dis[N];//切记!切记!一定要开long long!否则会卡第二个数据点
bool vis[N];//标记数组,用来标记走没走过
struct edge
{
    int to, w;
};
vector<edge> mp[N*5];//链式前向星数组

然后开始写迪杰斯特拉算法初始化部分

void dijkstra()
{
    for (int i = 1; i <= n; i++)
    {
        dis[i] = INF;
    }
    dis[s] = 0;
    int minj = 0;
    //以上全是初始化

dis数组千万记得开long long否则要爆掉的

接着就要开始写迪杰斯特拉算法核心逻辑部分

    for (int i = 1; i <= n; i++)
    {
        minj=0;//记得重置最小点变量minj的值
        for (int j = 1; j <= n; j++)
        {
            if (!vis[j] && (minj == 0 || dis[j] < dis[minj]))
            {
                minj = j;//找最小的点,且没有走过的的节点
            }
        }
        vis[minj] = true;//最小节点标记已走过
        for (int j = 0; j < mp[minj].size(); j++)//遍历以最小点为起点的所有边
        {
            if (dis[minj] + mp[minj][j].w < dis[mp[minj][j].to])//比较大小,决定要不进行松弛操作
                dis[mp[minj][j].to] = dis[minj] + mp[minj][j].w;//松弛操作
        }
    }

下面是本题的输出部分:

    for (int i = 1; i <= n; i++)
    {
        cout << dis[i] << " ";//输出
    }
}

本题主程序:

int main()
{
    int u, v;
    cin >> n >> m >> s;//输入点数,边数和起点
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;//输入起点、终点和权值
        mp[u].push_back((edge){v, w});//推入链式前向星数组
    }
    dijkstra();//运行算法
    return 0;
}

代码解释都打注释里了!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值