Dijksta(2)

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
数据范围:
1<=n<=m<=1.5*10^5
图中涉及边长均不小于0,且不超过10000

输入
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。

输出
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int head[150010]{ 0 }, weight[150010]{ 0 }, which[150010]{ 0 }, nex[150010]{ 0 };
int dis[150010];
bool shortest[150010]{ false };
int n, m, idx = 0;
void add(int x, int y, int c)       //邻接表实现存取,因为此题数据量为150000,邻接表空间为O(n),邻接矩阵空间为O(n^2),空间需要150000^2,显然会爆炸
{
    weight[idx] = c;            //weight存边的权重
    which[idx] = y;             //which存是指向那条边
    nex[idx] = head[x];         //模拟链表,先存的反而是最后的结点,后存的指向前面的结点(如果是第一个结点,那么为-1,指向空,如果不是第一个结点,那么不为-1,指向上一个插入的结点)
    head[x] = idx++;            //链表头,每次存入新结点就指向新结点
}
int dijkstra() {
    priority_queue<pair<int, int>,vector<pair<int,int>>,greater<pair<int,int>>> wait;    //小顶堆的写法,即优先队列的写法,每次去找最小元素时间为O(n^2),而用小顶堆时间只需O(nlogn)
    wait.push({ 0,1 });                                //先存距离,再存当前点是那个,因为greater<pair<int,int>>的比较方法是比较first
    while (wait.size()) {
        auto cur = wait.top();
        wait.pop();
        if (shortest[cur.second]) continue;        //可能有重边,而邻接表无法消除重边,但考虑到小顶堆特性,重边会优先出较小的那条,那么当较大那条出来时,该点已经能确认最小值了,就可以直接进行下一次循环
        shortest[cur.second] = true;               //小顶堆特性可知,第一次遇到的就是最优解了
        int temp = head[cur.second];               //temp是指针,是权重和指向边(即weight和which)的下标
        while (temp != -1) {
            if (!shortest[which[temp]] && dis[which[temp]] > cur.first + weight[temp]) {   //考虑当前指向的边是否已经确定是最短边了,以及当前点走过去的距离是否会小于指向的点的距离
                wait.push({ cur.first + weight[temp] ,which[temp] });
                dis[which[temp]] = cur.first + weight[temp];      //如果是,就更新
            }
            temp = nex[temp];                                         //指针后移
        }

    }
    if (dis[n] == 0x3f3f3f3f) return -1;                                      //如果终点没有被更新过,那么认定无法到达终点
    return dis[n];
}
int main() {
    scanf("%d %d", &n, &m);
    memset(dis, 0x3f, sizeof(dis));
    memset(head, -1, sizeof(head));
    dis[1] = 0;
    int a, b, c;
    for (int i = 0; i < m; ++i) {
        scanf("%d %d %d", &a, &b, &c);
        add(a, b, c);
    }
    cout << dijkstra() << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值