众所周知, 最短路是图论中非常常见的算法,而Dijkstra又作为常用的算法深受青睐
笔者希望通过该文让刚入门图论的新人能够对于迪杰斯特拉算法能有一个较为完整的认识
Let’s Start!
什么叫做最短路?
这是求出一个点到另一个点之间的最短距离,有些时候可以用DFS(搜索)来解决,但是针对一些特殊情况,比如没有方向或者有负权边的时候,用搜索就会很容易超时或者根本无法解决问题,因为搜索必须有明确的方向.
借用一段正规的定义
在一个无权的图中,若从一个顶点到另一个顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1。由于从一个顶点到另一个顶点可能存在着多条路径,每条路径上所经过的边数可能不同,即路径长度不同,把路径长度最短(即经过的边数最少)的那条路径叫作最短路径或者最短距离。
对于带权的图,考虑路径上各边的权值,则通常把一条路径上所经边的权值之和定义为该路径的路径长度或带权路径长度。从源点到终点可能不止一条路径,把带权路径长度最短的那条路径称为最短路径,其路径长度(权值之和)称为最短路径长度或最短距离。
在正式开始题目之前,请保证已经能够理解邻接表的使用
如果没有,可以先学习或者
看这篇博文
好,那就让我们进入第一道题
Dijkstra求最短路 Ⅰ–AcWing
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。
输入样例
3 3
1 2 2
2 3 1
1 3 4
输出样例
3
看到这个样例,也许你会觉得就这?
有手的都知道肯定是三啊
但如果我给你的是这个图,你又能否在第一时间看出正确答案呢?
是不是没有那么轻松呢
既然如此,那就进入我们的正题,即迪杰斯特拉算法到底是依靠什么来实现的
首先,我们需要一个数组dis,并用memset把它定义为0x3f(非常大)
int dis[100010];
memset(dis,0x3f,sizeof dis);
这个数组有什么用呢?
他是为了确定点1到点n(本文中所有的n均为点的个数)
之间是否存在一条通路,如果不存在那么
dis[n]=0x3f3f3f3f;
同理如果存在,那么所得到的是就是最短路径,其实不光光是n点,1-n之间任意一个点的最短路径都被储存在了数组里,神奇吧 =W=
这其实是一种最短路径树,那到底是如何实现的呢,让我们继续分析
为了方便后面的学习,我们直接使用堆优化过的迪杰斯特拉算法,采用这种优化的好处是
能够大大减小复杂度,能在很大程度上避免被TLE,当然如果出题人故意恶心你卡你那就没只能采取别的办法,当然会在后续专题中继续解决
如上所述,我们先建立一个递增堆并借用pair函数的帮助,你可能会问,为什么要用到pair,其实是因为我们希望输入进堆的包括当前节点pos以及前面已知的最短距离diss
#include <queue>
using namespace std;
typedef pair<int,int>PII;
priority_queue<PII,vector<PII>,greater<PII> >heap;
int diss1=heap.top().diss;
int pos1=heap.top().pos;
也许你也想用结构体表示
满足你!但是请先跟着学完再看
#include <cstdio>
struct node {
int diss,pos;
};
bool operator<(node x1,node x2) {
return x1.diss>x2.diss;
}
priority<node> heap;
int diss1=heap.top().diss;
int pos1=heap.top()