Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[pull] main from itcharge:main #196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
pull merged 2 commits into AlgorithmAndLeetCode:main from itcharge:main
May 30, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
更新「单源最短路径知识(一)」相关内容
  • Loading branch information
itcharge committed May 30, 2025
commit 02cf520ad693c5ae38a064114e1761bc61b42d33
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 1. 单源最短路径的定义
## 1. 单源最短路径简介

> **单源最短路径(Single Source Shortest Path)**:对于一个带权图 $G = (V, E),ドル其中每条边的权重是一个实数。另外,给定 $v$ 中的一个顶点,称之为源点。则源点到其他所有各个顶点之间的最短路径长度,称为单源最短路径。

Expand All @@ -20,34 +20,185 @@

> **Dijkstra 算法的算法思想**:通过逐步选择距离起始节点最近的节点,并根据这些节点的路径更新其他节点的距离,从而逐步找到最短路径。

Dijkstra 算法是一种用来解决单源最短路径问题的算法。这个算法适用于没有负权边的图。算法的核心思想是从源点出发,逐步找到到其他所有点的最短路径。它通过不断选择当前距离源点最近的节点,并更新与该节点相邻的节点的距离,最终得到所有节点的最短路径。

Dijkstra 算法使用贪心的策略。它每次选择当前未处理的节点中距离源点最近的节点,认为这个节点的最短路径已经确定。然后,它用这个节点的最短路径去更新其他相邻节点的距离。这个过程重复进行,直到所有节点的最短路径都被确定。

Dijkstra 算法的一个重要特点是它不能处理有负权边的图。因为负权边可能导致已经确定的最短路径被破坏。如果图中存在负权边,应该使用 Bellman-Ford 算法或 SPFA 算法。

### 2.2 Dijkstra 算法的实现步骤

1. 初始化距离数组,将源节点 $source$ 的距离设为 0ドル,ドル其他节点的距离设为无穷大。
2. 维护一个访问数组 $visited,ドル记录节点是否已经被访问。
3. 每次从未访问的节点中找到距离最小的节点,标记为已访问。
4. 更新该节点的所有相邻节点的距离。
5. 重复步骤 3ドル \sim 4,ドル直到所有节点都被访问。
6. 最后返回所有节点中最大的距离值,如果存在无法到达的节点则返回 $-1$。



### 2.3 Dijkstra 算法的实现代码

```python

class Solution:
def dijkstra(self, graph, n, source):
# 初始化距离数组
dist = [float('inf') for _ in range(n + 1)]
dist[source] = 0
# 记录已处理的节点
visited = set()

while len(visited) < n:
# 选择当前未处理的、距离源点最近的节点
current_node = None
min_distance = float('inf')
for i in range(1, n + 1):
if i not in visited and dist[i] < min_distance:
min_distance = dist[i]
current_node = i

# 如果没有可处理的节点(非连通图),提前结束
if current_node is None:
break

# 标记当前节点为已处理
visited.add(current_node)

# 更新相邻节点的距离
for neighbor, weight in graph[current_node].items():
new_distance = dist[current_node] + weight
if new_distance < dist[neighbor]:
dist[neighbor] = new_distance

return dist

# 使用示例
# 创建一个有向图,使用邻接表表示
graph = {
1: {2: 2, 3: 4},
2: {3: 1, 4: 7},
3: {4: 3},
4: {}
}
n = 4 # 图中节点数量
source = 1 # 源节点

dist = Solution().dijkstra(graph, n, source)
print("从节点", source, "到其他节点的最短距离:")
for i in range(1, n + 1):
if dist[i] == float('inf'):
print(f"到节点 {i} 的距离:不可达")
else:
print(f"到节点 {i} 的距离:{dist[i]}")
```

## 3. Bellman-Ford 算法
### 2.4 Dijkstra 算法复杂度分析

### 3.1 Bellman-Ford 算法的算法思想
- **时间复杂度**:$O(V^2)$
- 外层循环需要遍历所有节点,时间复杂度为 $O(V)$
- 内层循环需要遍历所有未访问的节点来找到距离最小的节点,时间复杂度为 $O(V)$
- 因此总时间复杂度为 $O(V^2)$

### 3.2 Bellman-Ford 算法的实现步骤
- **空间复杂度**:$O(V)$
- 需要存储距离数组 `dist`,大小为 $O(V)$
- 需要存储访问集合 `visited`,大小为 $O(V)$
- 因此总空间复杂度为 $O(V)$

### 3.3 Bellman-Ford 算法的实现代码

```python
## 3. 堆优化的 Dijkstra 算法

```
### 3.1 堆优化的 Dijkstra 算法思想

> **堆优化的 Dijkstra 算法**:通过使用优先队列(堆)来优化选择最小距离节点的过程,从而降低算法的时间复杂度。

## 4. SPFA 算法
在原始的 Dijkstra 算法中,每次都需要遍历所有未访问的节点来找到距离最小的节点,这个过程的时间复杂度是 $O(V)$。通过使用优先队列(堆)来维护当前已知的最短距离,我们可以将这个过程的时间复杂度优化到 $O(\log V)$。

### 4.1 SPFA 算法的算法思想
堆优化的主要思想是:
1. 使用优先队列存储当前已知的最短距离
2. 每次从队列中取出距离最小的节点进行处理
3. 当发现更短的路径时,将新的距离加入队列
4. 通过优先队列的特性,保证每次取出的都是当前最小的距离

### 4.2 SPFA 算法的实现步骤
### 3.2 堆优化的 Dijkstra 算法实现步骤

### 4.3 SPFA 算法的实现代码
1. 初始化距离数组,将源节点的距离设为 0ドル,ドル其他节点的距离设为无穷大。
2. 创建一个优先队列,将源节点及其距离 $(0, source)$ 加入队列。
3. 当队列不为空时:
- 取出队列中距离最小的节点
- 如果该节点的距离大于已知的最短距离,则跳过
- 否则,遍历该节点的所有相邻节点
- 如果通过当前节点到达相邻节点的距离更短,则更新距离并将新的距离加入队列
4. 重复步骤 3,直到队列为空
5. 返回所有节点的最短距离

### 3.3 堆优化的 Dijkstra 算法实现代码

```python
import heapq

class Solution:
def dijkstra(self, graph, n, source):
# 初始化距离数组
dist = [float('inf') for _ in range(n + 1)]
dist[source] = 0

# 创建优先队列,存储 (距离, 节点) 的元组
priority_queue = [(0, source)]

while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)

# 如果当前距离大于已知的最短距离,跳过
if current_distance > dist[current_node]:
continue

# 遍历当前节点的所有相邻节点
for neighbor, weight in graph[current_node].items():
distance = current_distance + weight
if distance < dist[neighbor]:
dist[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))

return dist

# 使用示例
# 创建一个有向图,使用邻接表表示
graph = {
1: {2: 2, 3: 4},
2: {3: 1, 4: 7},
3: {4: 3},
4: {}
}
n = 4 # 图中节点数量
source = 1 # 源节点

dist = Solution().dijkstra(graph, n, source)
print("从节点", source, "到其他节点的最短距离:")
for i in range(1, n + 1):
if dist[i] == float('inf'):
print(f"到节点 {i} 的距离:不可达")
else:
print(f"到节点 {i} 的距离:{dist[i]}")
```

代码解释:

1. `graph` 是一个字典,表示图的邻接表。例如,`graph[1] = {2: 3, 3: 4}` 表示从节点 1 到节点 2 的边权重为 3,到节点 3 的边权重为 4。
2. `n` 是图中顶点的数量。
3. `source` 是源节点的编号。
4. `dist` 数组存储源点到各个节点的最短距离。
5. `priority_queue` 是一个优先队列,用来选择当前距离源点最近的节点。队列中的元素是 (距离, 节点) 的元组。
6. 主循环中,每次从队列中取出距离最小的节点。如果该节点的距离已经被更新过,跳过。
7. 对于当前节点的每一个邻居,计算通过当前节点到达邻居的距离。如果这个距离比已知的更短,更新距离并将邻居加入队列。
8. 最终,`dist` 数组中存储的就是源点到所有节点的最短距离。

### 3.4 堆优化的 Dijkstra 算法复杂度分析

- **时间复杂度**:$O((V + E) \log V)$
- 每个节点最多被加入优先队列一次,每次操作的时间复杂度为 $O(\log V)$
- 每条边最多被处理一次,每次处理的时间复杂度为 $O(\log V)$
- 因此总时间复杂度为 $O((V + E) \log V)$

- **空间复杂度**:$O(V)$
- 需要存储距离数组,大小为 $O(V)$。
- 优先队列在最坏情况下可能存储所有节点,大小为 $O(V)$。

AltStyle によって変換されたページ (->オリジナル) /