没想到23个月没碰过最短路的我提交了4次就~直接过了!
顺便整理一下dijkstra的知识
本篇题解可能对题目阐述较少(?)
有错漏之处请及时通知,望海涵
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。这是从一个顶点到其余各顶点的最短路径算法,解决的是正权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止
dijkstra算法是一种非常巧妙的算法:
此算法可以在 $O((m+n)log n)$ 的时间复杂度内,解决正权图的单源最短路问题
$n$:节点个数 $m$:边的个数 $s$:起点编号 $e$:中点编号
$d[i]$:$distance$ 间距,表示当前从起点到点 $i$ 的最短路径的最小值
$v[i]$:$visit$ 访问,表示当前有没有访问(更新)节点 $i$
$struct$ $node$ { $int$ $to,$ $w$ }:$edge$ 边, $to$ 表示边的终点,$w$ 表示边的权值
$vector$ <$node$> $vec[i][j]$:$edge$ 存边(仅仅是作者习惯,向量命名为 $vec$ ),表示起点为 $i$ 的第 $j$ 条边 (终点为 $vec[i][j].to$,权值为 $vec[i][j].w$ )
首先我们观察 $d$ 数组与 $v$ 数组的定义
通过定义,明显可以得出:
//INF为极大值,n为节点个数,x为起点 void intt() { for(int i = 1;i <= n;++ i) d[i] = INF;//一开始,所有边都不与起点连通,所以距离设为无穷大 for(int i = 1;i <= n;++ i) v[i] = false;///一开始,所有边都不与起点连通 d[x] = 0;//起点到自己的距离为0 v[x] = true;//起点与自己连通 }
接着我们看到结构体 $node$ 和向量 $vec$
只要在输入每一条边时插入就彳亍了:
struct node {//node存放边 int to, w; //to表示路径终点,w表示路径权值 }; ...... int main() { cin >> n >> m >> s >> e;//输入 for(int i = 1, u, v, w;i <= m;++ i) {//u代表路径起点,v代表路径终点,w代表路径长度,m为边的个数 cin >> u >> v >> w; vec[u].push_back((node) {v, w});//建边 vec[v].push_back((node) {u, w});//建反边 //因为是无向图,建两条边,有向图就只用建一条 } }
建议联系上两个小节内容,更容易理解
我们先观察一个比较简单的图:
我们观察节点1到节点3的最短路:很明显路径顺序为1 -> 4 -> 3
我们再手算求出 $d$ 数组的值:
$d[1]$ $=$ $0,$ $d[2]$ $=$ $3,$ $d[3]$ $=$ $11,$ $d[4]$ $=$ $4$(很显然,$d[3] = ans$)
那么如何编程求 $d$ 数组的值呢?
结论一:$d[i] = Min(d[u] + w[u$ -> $u])$(假设此时 $Min(d[u] + w[u$ -> $u])$ 可以被推出来)
注:$u \in$ 以 $i$ 为一端点的边的端点,$w[u$ -> $v]$ 表示以 $u, v$ 为端点的边的权值
比如,d[2] = min(d[1] + 3, d[3] + 10)
结论二:最短路径为简单路径!
注意我们讨论的是正权图
直观上理解,就是如果有环,那么把环去掉,最短路径长度更短
证明可以参考:(不是吧,我竟然没找到qwq)
$dijkstra$ 的算法流程如下:
1.初始化:可以参考 2.3 小节,将起点插入集合 $S$
2.维护:将所有集合 $S$ 中的点集划分成两个集合,已更新的集合和未更新的集合
3.查询:在已更新的集合中,找到 $d$ 数组值最小的点,没有就退出循环
4.更新:$d[x]$ 已经是目前 $x$ 的最短路径了! 更新所有 $x$ 的出边
5.返回:将点 $x$ 推出集合,将所有刚更新的点加入集合
当然,我们可以用优先队列与 $v$ 数组来更快的执行返回操作
题目:求出 1 到所有结点最短路的值
首先,分析初始全局变量:
$vec[1][0] = $
$d[1] = 0$, $d[2] = INF$, $d[3] = INF$, $d[4] = INF$, $d[5] = INF$
$v[1] = true$, $v[2] = false, $v[3] = false$, $v[4] = false$, $v[5] = false$