最短路径-Dijkstra算法,以洛谷P4779 【模板】单源最短路径(标准版)为例

Dijkstra算法

条件

处理 图 的单源最短路且边权均为非负的情况

例题和代码

例题

链接:洛谷P4779

image

代码

/*
 * 将所有路径以二元组(路径长度,终点)的形式放入以路径长度为关键字的小根堆中,每次取出堆顶元素,查看该终点是否已确定最短路。同时删除堆顶。
 *(1)已确定 则不做处理
 *(2)未确定,确定该点最短路,并进行松弛操作:遍历该点所有出边,查看是否能更新相邻点的最短路,若产生更新则将新的最短路加入堆。
 * 一直处理到堆为空则所有点的最短路均被确定。
 */

/*
 * 采用 边集 和 链式前向星 的方法来记录 图
 */

#include <iostream>
#include <algorithm>
#include <queue>

#define N 200005 // 共有1e5个点
using namespace std;

int n, m, rt, dis[N], l_id, head[N];
// n 个点,m 条路径,均为有向非负权,rt 原点是哪一个
// dis 用来存储每个点的最短路,dis数组开始时候会被赋值为无穷大
// l_id 和 head 均是用来实现存边操作的数组,l_id 为边的id  (边集和链式前向星)

// 用边集来存储边
// head[u] 的含义是一条从 u 射出的边的编号. id, 则 Edge[id] 编号为id的那条边
// edge[i].to表示第i条边的终点,edge[i].next表示与第i条边同起点的下一条边的存储位置,edge[i].w为边权值
struct EDGE
{ // 存边的结构体
    int to, next, vlu;
    // to: 去哪个点 next 下一条边 ,vlu 这条边的权重
} Edge[N];

void add(int u, int v, int vlu)
{ // 添加边,表示从 u 到 v 的一条权值为 vlu 的边
    Edge[++l_id].to = v;
    Edge[l_id].next = head[u];
    head[u] = l_id;
    Edge[l_id].vlu = vlu;
}

const int MAXN = 2e9;
bool vis[N]; // 标记第N个点是否已经找到最短距离

struct node
{ //结构体用来存放二元组,这个二元组是 终点,路径长度(权重)
    // id 该二元组指向的终点是哪一个,vlu 这条路径的长度(权重)
    int id, vlu;
};

bool operator<(node x, node y)
{ // 重载运算符,将小于号变为大于号,使得后续可以将STL中的大根堆变为小跟堆
    return x.vlu > y.vlu;
}

int main()
{
    scanf("%d%d%d", &n, &m, &rt);
    for (int i = 1; i <= n; i++)
        dis[i] = MAXN;
    for (int i = 1; i <= m; i++)
    {
        int x, y, v;
        scanf("%d%d%d", &x, &y, &v);
        add(x, y, v);
    }
    priority_queue<node> q; // 小跟堆
    q.push((node){rt, 0});
    dis[rt] = 0;
    while (!q.empty())
    {
        node x = q.top();
        q.pop();
        if (vis[x.id])
            continue;
        vis[x.id] = 1;
        for (int i = head[x.id]; i; i = Edge[i].next)
        {
            int v = Edge[i].to;
            if (vis[v])
                continue;
            if (dis[v] > dis[x.id] + Edge[i].vlu)
            {
                q.push((node){v, x.vlu + Edge[i].vlu});
                dis[v] = x.vlu + Edge[i].vlu;
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        printf("%d ", dis[i]);
    }
    return 0;
}
posted @ 2022-01-25 20:48  诗子黎  阅读(85)  评论(0编辑  收藏  举报