最短路总结1 最短路问题概述与朴素dijkstra

最短路系列链接
最短路总结1 最短路问题概述与朴素dijkstra
最短路总结2 堆优化dijkstra
最短路总结3 BellmanFord
最短路总结4 SPFA及应用
最短路总结5 floyd

1.最短路问题概述

若网络中的每条边都有一个数值(长度、成本、时间等),则找出两节点(通常是源节点和阱节点)之间总权和最小的路径就是最短路问题。

最短路问题,其实就是给定一个网络,给定一个或一组起点(术语叫源点),对这些源点给定其他点,询问这些点到源点的最短路径。

2. 分类


Notes:

  1. 单源是指单一起点到其他点的最短路,多源是指求每组起点到终点的最短路。

  2. 堆优化dijkstra是在朴素版基础上,利用小根堆的自动维持顺序的特性优化朴素版中的某一步。

  3. SPFA算法一般不论稠密图还是稀疏图,都用邻接矩阵存储图。

  4. SPFA算法本质上是利用宽搜的思想对 bellerman-ford算法做的优化,因此SPFA很强大,在绝大多数情况下可以用SPFA算法代替bellman-ford算法解决问题,因此重点掌握。(其实也可以代替dijkstra)

  5. SPFA算法的局限:当图中出现一下两点之一时SPFA算法失效,只能使用bellman-ford算法。
    (1)限制最短路的路径经过不超过k条边
    (2)图中存在负权回路(回路边权之和为负数)

  6. SPFA算法可以用来判断是否存在负环,另:判断正环用tanjar算法

3.朴素dijkstra算法(On^2+m)
  1. 初始化各点到源点的距离
  2. 迭代n-1次(除源点外有n-1个点)
    (1)在最短路未确定的点中,找距离源点最近的点v。(用bool数组标识该点的最短路是否已经确定)
    (2)用v点去更新全图所有点的当前最短路距离(dist[])
    (3)若i点满足:dist[i] > dist[v] + w[v][i]则更新i点的dist值
    更新全图后将该点设置为最短路已经确定
    在这里插入图片描述
    这里假设找到的v点是2点,用2点去更新全图,实际上这里就是更新3点,也就相当于判断这两条到路径谁更短:(1)1->2->3距离为dist[2]+w[2][3](2)1->3距离为dist[3]。推广到更大更复杂的网络中,也是一个个类似这样去比较更新,比较完所有点,则v点不可能再被更新,所以设置v点的最短路已经确定。
4.模板
int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定
// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
       // 用t更新其他点的距离
       for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);
       st[t] = true;
     }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
5.板子题

给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
输入格式
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。
数据范围
1≤n≤5001≤n≤500,
1≤m≤1051≤m≤105,
图中涉及边长均不超过10000。
输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>

using namespace std;

const int N=550,inf=0x3f3f3f3f;
int n,m;
int g[N][N];
int dist[N];
bool st[N];
int dijkstra() {
    //1.初始化  
    memset(dist,inf,sizeof(dist));
    dist[1]=0;
    //2.迭代n-1次
    for(int i=0;i<n;i++) {
        //3.在未确定最短路的点中找到距离源点最近的点
        int t=-1;
        for(int i=1;i<=n;i++) 
            if(!st[i] && (t==-1 || dist[i]<dist[t])) 
                t=i;
        //4.用找到的点去更新全图
         for(int i=1;i<=n;i++) {
            dist[i]=min(dist[i],dist[t]+g[t][i]);
        }
        
        st[t]=1;
    }
    if(dist[n]>=1000000000) return -1;
    else return dist[n];
    
}
int main()
{
    cin >> n >> m;
    memset(g,inf,sizeof(g));
    while(m --) {
        int x,y,z;
        cin >> x >> y >> z;
        
        if(x!=y) {
            g[x][y]=min(g[x][y],z);
        }
    }
    int t=dijkstra();
    cout<<t;
    
    return 0;
}

6.小细节
  1. 去重边:在存储图时,取两点之间多条边的最短的那条
  2. 去自环:在存储图时,自己到自己的边应当去除
  3. 无向边:区别只在于存储图的时候,存两边,一去一回。
 int x,y,z;
 cin >> x >> y >> z;
        
if(x!=y) {
      g[x][y]=min(g[x][y],z);
}
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值