Java教程

dijkstra 学习笔记(未更完)

本文主要是介绍dijkstra 学习笔记(未更完),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

0 题外话

没想到23个月没碰过最短路的我提交了4次就~直接过了!

顺便整理一下dijkstra的知识

本篇题解可能对题目阐述较少(?)

有错漏之处请及时通知,望海涵


1 引入

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。这是从一个顶点到其余各顶点的最短路径算法,解决的是正权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止


2 算法介绍

dijkstra算法是一种非常巧妙的算法:

此算法可以在 $O((m+n)log n)$ 的时间复杂度内,解决正权图的单源最短路问题

2.1 基础变量介绍

$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$ )

2.2 变量初始化

首先我们观察 $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});//建反边
		//因为是无向图,建两条边,有向图就只用建一条
	}
}

2.3 算法原理

建议联系上两个小节内容,更容易理解

我们先观察一个比较简单的图:

图一

我们观察节点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)

3 算法详解

3.1 算法流程:

$dijkstra$ 的算法流程如下:

1.初始化:可以参考 2.3 小节,将起点插入集合 $S$

2.维护:将所有集合 $S$ 中的点集划分成两个集合,已更新的集合和未更新的集合

3.查询:在已更新的集合中,找到 $d$ 数组值最小的点,没有就退出循环

4.更新:$d[x]$ 已经是目前 $x$ 的最短路径了! 更新所有 $x$ 的出边

5.返回:将点 $x$ 推出集合,将所有刚更新的点加入集合

当然,我们可以用优先队列与 $v$ 数组来更快的执行返回操作

3.2 样例详解

图一

题目:求出 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$

这篇关于dijkstra 学习笔记(未更完)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!