算法笔记——堆优化的Dijkstra求解最短路径

就是求1到n的最短路径;输入是n,m;然后是m条边的信息

算法如下:

#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N = 10010;

int n, m;
int h[N], e[N], ne[N],w[N],idx;
int dist[N];
int ans = N;
//邻接表存储,每个结点都会有一个链表
//h[i]存的是i号链表头指向哪个结点,指向null的话就是-1
//e来存这条边指向哪个结点,1指向2,则存2
//w来存这条边的权值是多少,1指向2且权值为10,则存10
//ne来存链表上下一个是几号结点
//idx表示现在用到了哪个下标

typedef pair<int,int> PII;

bool st[N];
void add(int a, int b,int c) //添加一条从结点a到结点b的边,权值为c
{//在a链表的表头插入
    e[idx] = b;   //先将b存入结点idx中
    w[idx] = c; //c是a指向b这条边的权值
    ne[idx] = h[a];   //将idx结点的指针指向h原本指向的地方
    h[a] = idx;//将h指向新加进来的这个idx结点上
    idx++;
}

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    priority_queue < PII, vector<PII>, greater<PII>>heap; //一个优先队列,默认是大根堆less,greater是小根堆
    heap.push({ 0,1 });//第一个结点的内容;(起点到该点的距离值,结点编号)

    while (heap.size())
    {
        auto t = heap.top(); //取出最小的顶点作为中间结点,第一次就是即1号结点自己
        heap.pop();//从堆中删掉

        int distance = t.first, ver = t.second; //t的第一个元素是从原点到结点编号的距离,第二个元素是结点编号
        if (st[ver]) continue;

        for (int i = h[ver]; i != -1; i = ne[i]) //现在ver号结点是中间结点,要利用这个中间结点来更新整个dist
        {//遍历这一个链表,不要想的这么具体,就是遍历一个单链表,
        //每个结点两个值,一个编号e[i],一个从表头结点到该节点的距离w[i]
            int j = e[i]; 
            if (dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({ dist[j], j });
            }

        }
    }
    if (dist[n] == 0x3f3f3f3) return -1;
    return dist[n];

}

int main()
{
    scanf_s("%d %d", &n, &m);//几个点 几条边
    memset(h, -1, sizeof h); //每个链表的表头都指向null
    int a, b, c;
    while (m--)
    {
        scanf_s("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }

    int d = dijkstra();
    printf("%d\n", d);



}

/*
5 7
1 2 19
1 4 20
2 3 15
3 5 16
4 2 18
2 3 14
4 5 13
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值