#单源最短路 #Dijkstra 学习心得 20.8.13

最短路

最短路学习思路图

朴素Dijkstra

链接
1、思路
*0、定义数组 dis[n] (从1到其它点的距离), s[n](已经确定最短距离的点);
*1、初始化 dis[1] = 0, dis[其它点] = 正无穷;
*2、 for(1 ~ n);——————————循环 n 次,更新所有的点 t;
*3 找到 不在s中的,距离最近的点 t;
*4 将t加入s;
*5 用t更新其它点的距离;————————循环n次
(这里是两 层 循环, 所以时间复杂度是 n^2)
*6 返回

例题
#include<bits/stdc++.h>
using namespace std;
const int N = 510;

int n, m;
int g[N][N];
int djs[N];
bool s[N];

int djst(){
    memset(djs, 0x3f3f3f3f, sizeof djs);				/* *1 */
    djs[1] = 0;											/* *1 */
    
    for(int i = 0; i < n; i ++){						/* *2 */
        int t = -1;										/* *3 */
        for(int j = 1; j <= n; j ++)					/* *3 */
            if(!s[j] && (t == -1 || djs[t] > djs[j]))	/* *3 */ 
                t = j;									/* *3 */
            
        s[t] = 1;										/* *4 */
        
        for(int j = 1; j <= n; j ++)					/* *5 */
            djs[j] = min(djs[j], djs[t] + g[t][j]);		/* *5 */
    }
    if(djs[n] == 0x3f3f3f3f) return -1;					/* *6 */
    return djs[n];										/* *6 */
}

int main(){
    cin >> n >> m;
    memset(g, 0x3f3f3f3f, sizeof g);
    while(m --){
        int a, b, c;
        cin >> a >>b >>c;
        g[a][b] = min(g[a][b], c);
    }
    int t = djst();
    
    cout << t;
    
    return 0;
}
/*
0x3f3f3f3f 代表 正无穷。
*/

优化Dijkstra :

题目链接
优先队列的函数补充:
优先队列数据结构(堆)的函数用法 20.10.17

可以更新的地方:
分析:


*2、 for(1 ~ n);·;
*3	找到 不在s中的,距离最近的点 t;——————*2、*3共循环 n^2 次来找点 t;(用小根堆堆来做可时间O(n))
	,也就是用优先队列,优化后为O(log n)
	就是这里可以优化
 for(int j = 1; j <= n; j ++)					/* *3 */
            if(!s[j] && (t == -1 || djs[t] > djs[j]))	/* *3 */ 
                t = j;			
*4	将t加入s;																		——————————————————这里是n次
*5	用t更新其它点的距离;						—————————————具体操作时m次,遍历所有的边来更新
堆优化后 整个计算量最大是 O(m log n)。
堆的写法:
手写或用优先队列,两者时间是一个级别的,用优先队列,不需要手写堆。
#include<bits/stdc++.h>
using namespace std;
const int N = 150010;

int n, m;
int djs[N];
bool st[N];
int ne[N], e[N], h[N], w[N], idx = 0;

typedef pair<int ,int> P;//距离1的距离,以及点号, 这里默认是按照第一个元素来排序的

void add(int a, int b, int c){
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

int djst(){
    memset(djs, 0x3f, sizeof djs);
    djs[1] = 0;
    
    priority_queue< P, vector<P>, greater<P> > heap;/* *1 */
    heap.push( {0, 1} );
    
    while(heap.size()){
        auto t = heap.top();
        heap.pop();
        
        int ver = t.second, distance = t.first;
        if(st[ver]) continue;
        
        st[ver] = 1;								/* *2 */
        
        for(int i = h[ver]; i != -1; i = ne[i]){
            int j = e[i];
            if(djs[j] > distance + w[i]){
                djs[j] = distance + w[i];
                heap.push({djs[j], j});
            }
        }
    }       
   
    if(djs[n] == 0x3f3f3f3f) return -1;
    return djs[n];
}

int main(){
    cin >> n >> m;
    memset(h, -1, sizeof h);
    while(m --){
        int a, b, c;
        cin >> a >>b >>c;
        add(a, b, c);
    }
    cout << djst() << endl;
    return 0;
}

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。

请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。

输入格式
第一行包含整数n和m。

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

输出格式
输出一个整数,表示1号点到n号点的最短距离。

如果路径不存在,则输出-1。

数据范围
1≤n,m≤1.5×105,
图中涉及边长均不小于0,且不超过10000。

输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3
*1 强调:“>”不要两个拼在一起。
less是从大到小,greater是从小到大。
第一个参数为数据类型。
第二个参数为容器类型。
第三个参数为比较函数。
*2 千万不要忘记。

原文地址:https://www.cnblogs.com/yuanyulin/p/14026759.html