最短路径算法大冒险:从迷宫小白到图论忍者(超豪华扩展版)China and English

🚀 最短路径算法大冒险:从迷宫小白到图论忍者(超豪华扩展版)

文章目录

警告:阅读本文可能导致以下副作用:看到地图就想计算最优路径、用算法思维规划外卖路线、在约会中突然大喊"这就是负权环!"。请自备咖啡因,系好安全带,我们起飞啦!


🧩 第一章:图论宇宙的基石(超扩展版)

1.1 什么是图?(不是你想的那种!)

G = (V, E)顶点的集合 V边的集合 E 组成的数学结构,其中:

  • 顶点 (Vertex):宇宙中的关键节点,比如你的前任、现任和潜在对象
    V = { v 1 , v 2 , … , v n } V = \{v_1, v_2, \dots, v_n\} V={v1,v2,,vn}
  • 边 (Edge):节点间的连接通道,比如你和前任之间的"微信删除"边
    E ⊆ { ( u , v ) ∣ u , v ∈ V } E \subseteq \{ (u,v) \mid u,v \in V \} E{(u,v)u,vV}
爬行 10min
冲刺 2min
灵魂出窍 8hr
蠕动 1hr
你的床
厕所
公司打卡机
下班
1.2 权值:世界的"代价度量"

每条边可携带权值 w: E → ℝ,代表:

  • 距离成本:w(北京, 上海) = 1200km
  • 时间成本:w(起床, 上班) = 痛苦系数 8.5
  • 经济成本:w(求婚, 结婚) = $$$$...
  • 情感成本:w(你, 初恋) = 1000点伤害

权值可以是负数! 比如:w(老板, 加薪) = -1000元(因为钱从老板口袋流到你口袋)

[ 床 厕所 公司 下班 床 0 10 ∞ ∞ 厕所 ∞ 0 2 ∞ 公司 ∞ ∞ 0 480 下班 60 ∞ ∞ 0 ] \begin{bmatrix} & \text{床} & \text{厕所} & \text{公司} & \text{下班} \\ \text{床} & 0 & 10 & \infty & \infty \\ \text{厕所} & \infty & 0 & 2 & \infty \\ \text{公司} & \infty & \infty & 0 & 480 \\ \text{下班} & 60 & \infty & \infty & 0 \\ \end{bmatrix} 厕所公司下班060厕所100公司20下班4800


🚶 第二章:广度优先搜索(BFS)——地毯式搜素(超扩展版)

2.1 算法核心:平等主义的探索
def BFS(G, start):
    queue = deque([start])          # 初始化队列,起点入队
    visited = {start: 0}            # 记录距离,起点为0
    parent = {start: None}          # 记录父节点
    
    while queue:
        u = queue.popleft()         # 取队首,公平对待每一个节点
        for v in neighbors(u):      # 扫描邻居
            if v not in visited:
                visited[v] = visited[u] + 1  # ⭐关键步骤!距离+1
                parent[v] = u       # 记录爸爸是谁
                queue.append(v)
    return visited, parent
2.2 数学本质:波前传播模型

距离公式:
d ( v ) = min ⁡ u ∈ prev ( v ) { d ( u ) + 1 } d(v) = \min_{u \in \text{prev}(v)} \{ d(u) + 1 \} d(v)=uprev(v)min{d(u)+1}

甘特图:BFS的时间征服史

40秒 第0秒 第1秒 第2秒 第3秒 起点A 节点B 节点C 节点D 节点E 节点F 终点G 层级0 层级1 层级2 层级3 BFS征服时间线

现实应用

  • 微信朋友圈关系链(6度空间理论验证)
  • 病毒传播模型(别慌,是计算机病毒!)
  • 寻找最近的厕所(紧急情况!)

⚡ 第三章:Dijkstra 算法——谨慎的征服者(超扩展版)

3.1 核心思想:贪心策略的完美演绎

“永远吃掉离你最近的巧克力,直到发现更近的新巧克力”

def Dijkstra(G, start):
    dist = {v: float('inf') for v in G}  # 初始化距离为无穷,表示未知
    dist[start] = 0
    heap = [(0, start)]                  # 最小堆加速,存储(距离,节点)
    path_tracker = {start: []}           # 路径跟踪器
    
    while heap:
        d_u, u = heapq.heappop(heap)     # 取出当前距离最小的节点
        if d_u != dist[u]: continue      # 过时信息跳过(重要优化!)
        
        for v, w in neighbors(u):        # 遍历邻居
            new_dist = dist[u] + w       # ⭐松弛操作!尝试更新距离
            if new_dist < dist[v]:
                dist[v] = new_dist
                path_tracker[v] = path_tracker[u] + [u]  # 更新路径
                heapq.heappush(heap, (new_dist, v))  # 加入堆
    return dist, path_tracker
3.2 数学原理:最优子结构证明

松弛操作(Relaxation):
δ ( v ) = min ⁡ ( δ ( v ) , δ ( u ) + w ( u , v ) ) \delta(v) = \min \left( \delta(v), \delta(u) + w(u,v) \right) δ(v)=min(δ(v),δ(u)+w(u,v))

定理:当所有边权非负时,Dijkstra 算法总能找到最短路径。

甘特图:Dijkstra的征服时刻表

gantt
    title Dijkstra的征服时刻表
    dateFormat  ss
    axisFormat %S秒
    
    section 节点占领
    起点A : done, a0, 0, 1
    节点B (距离2) : active, a1, 1, 2
    节点C (距离4) : crit, a2, 2, 3
    节点D (距离5) : crit, a3, 3, 4
    终点E (距离7) : milestone, a4, 4, 5
    
    section 堆操作
    初始堆[A:0] : a0, 0, 1
    弹出A,加入B:2, C:4 : a1, 1, 2
    弹出B,加入D:5 : a2, 2, 3
    弹出C,无更新 : a3, 3, 4
    弹出D,加入E:7 : a4, 4, 5

血泪教训
当你试图用Dijkstra计算"股票套利路径"时——

负权边会让Dijkstra崩潰! 因为它假设了非负权值。


🕵️ 第四章:Bellman-Ford 算法——疑心病侦探(超扩展版)

4.1 算法设计:暴力美学
def BellmanFord(G, start):
    dist = {v: float('inf') for v in G}
    dist[start] = 0
    parent = {start: None}
    
    # 第一阶段:V-1轮松弛(V为顶点数)
    for i in range(len(G)-1):           # ⭐关键循环,进行V-1轮
        updated = False
        for u in G:
            for v, w in neighbors(u):
                if dist[u] + w < dist[v]:
                    dist[v] = dist[u] + w   # 松弛
                    parent[v] = u
                    updated = True
        if not updated: break  # 提前终止优化
        
    # 第二阶段:检测负权环
    for u in G:
        for v, w in neighbors(u):
            if dist[u] + w < dist[v]:   # 还能松弛?
                raise "发现负权环!路径不存在!"
    return dist, parent
4.2 数学本质:动态规划优化

路径长度上界引理:经过 k 轮松弛后,算法找到所有长度不超过 k 的最短路径。

甘特图:Bellman-Ford的侦查进度

gantt
    title Bellman-Ford的侦查进度
    dateFormat  ss
    axisFormat %S秒
    
    section 松弛轮次
    第1轮 : a1, 0, 5
    第2轮 : a2, 5, 10
    第3轮 : a3, 10, 15
    ...
    第V-1轮 : a4, after a3, 5
    
    section 检测内容
    直接邻居 : done, a1, 0, 5
    2跳邻居 : active, a2, 5, 10
    3跳邻居 : crit, a3, 10, 15
    全图覆盖 : milestone, a4, 15, 20
    
    section 负权环检测
    最后检查 : crit, after a4, 5

现实映射

  • 金融套利检测(负权环 = 无限套利机会)
  • 游戏中的伤害增益循环(“永生bug”)
  • 时间旅行悖论(如果你回到过去杀死祖父,你会消失吗?)

🔥 第五章:SPFA 算法——Bellman-Ford 的社牛版(超扩展版)

5.1 优化思想:队列驱动的松弛
def SPFA(G, start):
    dist = {v: float('inf') for v in G}
    dist[start] = 0
    queue = deque([start])
    in_queue = set([start])             # 避免重复入队
    count = {v: 0 for v in G}           # 入队次数计数器
    
    while queue:
        u = queue.popleft()
        in_queue.remove(u)
        
        for v, w in neighbors(u):
            new_dist = dist[u] + w
            if new_dist < dist[v]:
                dist[v] = new_dist
                if v not in_queue:      # 只添加未在队列中的节点
                    count[v] += 1
                    if count[v] > len(G):  # 检测负权环
                        raise "发现负权环!"
                    queue.append(v)
                    in_queue.add(v)
    return dist
5.2 性能分析:最坏 vs 平均

甘特图:SPFA的派对邀请名单

40秒 初始队列[A] A出队,邀请B,C B出队,邀请D C出队,邀请E D出队,无新邀请 E出队,派对结束 A B C D E 队列状态 入队次数 SPFA的派对邀请名单
场景时间复杂度表现
稀疏图O(kE)闪电侠速度 🚀
网格图O(VE)正常人类速度 👨💻
刻意构造图O(VE)蜗牛速度 🐌
存在负权环永动机警告 ⚠️

冷知识:SPFA 的发明者段凡丁在1994年发表论文时,可能正在吃火锅 🍲


🌌 第六章:Floyd-Warshall 算法——全知全能上帝视角(超扩展版)

6.1 动态规划三循环之美
def FloydWarshall(G):
    n = len(G)
    dist = [[float('inf')] * n for _ in range(n)]
    path = [[None] * n for _ in range(n)]  # 路径追踪
    
    # 初始化:直接邻居
    for i in range(n):
        dist[i][i] = 0
        for j, w in G[i].items():
            dist[i][j] = w
            path[i][j] = i
            
    # 动态规划核心:k为中继节点
    for k in range(n):              # 中继节点
        for i in range(n):          # 起点
            for j in range(n):      # 终点
                if dist[i][k] + dist[k][j] < dist[i][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]  # ⭐更新距离
                    path[i][j] = path[k][j]  # 更新路径
    return dist, path
6.2 数学本质:路径空间分解

定义 d ( k ) ( i , j ) d^{(k)}(i,j) d(k)(i,j) 为只经过节点 1 , 2 , . . . , k {1,2,...,k} 1,2,...,k i → j i→j ij 最短路径

状态转移方程
d ( k ) ( i , j ) = min ⁡ ( d ( k − 1 ) ( i , j ) , d ( k − 1 ) ( i , k ) + d ( k − 1 ) ( k , j ) ) d^{(k)}(i,j) = \min \left( d^{(k-1)}(i,j), d^{(k-1)}(i,k) + d^{(k-1)}(k,j) \right) d(k)(i,j)=min(d(k1)(i,j),d(k1)(i,k)+d(k1)(k,j))

甘特图:Floyd的宇宙构建计划

gantt
    title Floyd的宇宙构建计划
    dateFormat  ss
    axisFormat %S秒
    
    section 中继节点
    节点0 : a0, 0, 10
    节点1 : a1, 10, 20
    节点2 : a2, 20, 30
    ... 
    节点n-1 : an, after a2, 10
    
    section 知识积累
    直接连接 : done, a0, 0, 10
    1跳路径 : active, a1, 10, 20
    2跳路径 : crit, a2, 20, 30
    全知全能 : milestone, an, 30, 40

震撼事实
在 1000 个顶点的图上运行 Floyd,循环次数 = 10亿次!
相当于让地球70亿人每人帮你计算14次加法 😱


🎯 第七章:A* 算法——带导航的智能搜索(超扩展版)

7.1 启发式搜索:给Dijkstra装GPS
def A_star(G, start, goal, heuristic):
    open_set = PriorityQueue()
    open_set.put((0, start))
    g_score = {v: float('inf') for v in G}
    g_score[start] = 0
    f_score = {v: float('inf') for v in G}
    f_score[start] = heuristic(start, goal)
    came_from = {}
    
    while not open_set.empty():
        _, current = open_set.get()
        if current == goal:
            return reconstruct_path(came_from, current)
        
        for neighbor, w in neighbors(current):
            tentative_g = g_score[current] + w
            if tentative_g < g_score[neighbor]:
                came_from[neighbor] = current
                g_score[neighbor] = tentative_g
                f_score[neighbor] = tentative_g + heuristic(neighbor, goal)
                if neighbor not in open_set:
                    open_set.put((f_score[neighbor], neighbor))
    return failure
7.2 启发函数设计艺术

可接受性(Admissible):
h ( v ) ≤ 实际距离 ( v , g o a l ) h(v) \leq \text{实际距离}(v, goal) h(v)实际距离(v,goal)

一致性(Consistent):
h ( u ) ≤ w ( u , v ) + h ( v ) h(u) \leq w(u,v) + h(v) h(u)w(u,v)+h(v)

甘特图:A*的智能导航

40秒 起点A (f=5) 节点B (f=5) 节点C (f=6) 节点D (f=4) 终点Goal (f=0) h(A)=5 h(B)=3 h(C)=2 h(D)=1 h(Goal)=0 节点探索 启发函数 A*的智能导航

经典启发函数

  • 曼哈顿距离:h(a,b) = |x₁-x₂| + |y₁-y₂| (只能上下左右移动)
  • 欧几里得距离:h(a,b) = √((x₁-x₂)² + (y₁-y₂)²) (直线距离)
  • 切比雪夫距离:h(a,b) = max(|x₁-x₂|, |y₁-y₂|) (国王移动,8方向)

🏆 第八章:算法选美大赛(超扩展版)

8.1 场景适配指南
算法最佳场景最怕场景性格分析
BFS无权图社交关系加权图单纯直接
Dijkstra正权图路由规划负权边谨慎乐观
Bellman-Ford带负权金融模型稠密图多疑谨慎
SPFA稀疏图快速求解刻意构造的毒瘤数据投机分子
Floyd小规模全源最短路大规模图全能但反应慢
A*路径规划有启发信息无良好启发函数聪明但依赖导航
8.2 复杂度终极对决

算法 时间复杂度 空间复杂度 魔法值 BFS O ( V + E ) O ( V ) ✨ Dijkstra O ( ( V + E ) log ⁡ V ) O ( V ) ✨✨ Bellman-Ford O ( V E ) O ( V ) ✨✨✨ SPFA O ( V E ) → O ( k E ) O ( V ) ✨✨✨✨ Floyd-Warshall O ( V 3 ) O ( V 2 ) ✨ A* O ( b d ) O ( b d ) 依赖h \begin{array}{c|c|c|c} \text{算法} & \text{时间复杂度} & \text{空间复杂度} & \text{魔法值} \\ \hline \text{BFS} & O(V+E) & O(V) & ✨ \\ \text{Dijkstra} & O((V+E)\log V) & O(V) & ✨✨ \\ \text{Bellman-Ford} & O(VE) & O(V) & ✨✨✨ \\ \text{SPFA} & O(VE) \rightarrow O(kE) & O(V) & ✨✨✨✨ \\ \text{Floyd-Warshall} & O(V^3) & O(V^2) & ✨ \\ \text{A*} & O(b^d) & O(b^d) & \text{依赖h} \\ \end{array} 算法BFSDijkstraBellman-FordSPFAFloyd-WarshallA*时间复杂度O(V+E)O((V+E)logV)O(VE)O(VE)O(kE)O(V3)O(bd)空间复杂度O(V)O(V)O(V)O(V)O(V2)O(bd)魔法值✨✨✨✨✨✨✨✨✨依赖h

8.3 甘特图:算法竞赛表现
00秒 00秒 00秒 00秒 00秒 00秒 大图(5000节点) 大图 小图(50节点) 中图(500节点) 小图 中图 小图 中图 大图 小图 中图 大图 BFS Dijkstra SPFA Floyd 算法竞赛表现对比

🚨 第九章:负权环——图论中的黑洞(超扩展版)

9.1 识别技术对比
方法原理效率
Bellman-Ford第V轮还能松弛O(VE)
SPFA节点入队次数>VO(VE)
Tarjan强连通在强连通分量中检测负环O(V+E)
9.2 负权环的哲学思考

“沿着负权环无限循环,就像在爱情中不断付出却越爱越深——看似收益递增,实则陷入死循环”

数学表达:
∃  cycle  C : ∑ e ∈ C w ( e ) < 0 \exists \text{ cycle } C: \sum_{e \in C} w(e) < 0  cycle C:eCw(e)<0

甘特图:负权环的死亡漩涡

40秒 40秒 节点A→B B→C C→A A→B B→C C→A ... 循环1 循环2 循环n 负权环的死亡漩涡

🌟 第十章:实战特训营(超扩展版)

10.1 经典问题破解
  1. 多源最短路
    🔥 解决方案:Floyd-Warshall 或 |V| 次 Dijkstra

  2. 第K短路
    💡 解决方案:A* 算法的变种,每次找到一条路径后继续搜索,直到找到K条。

  3. 差分约束系统
    ⚙️ 建模:
    x j − x i ≤ c k ⇒ 边 ( i , j )  权值  c k x_j - x_i \leq c_k \Rightarrow \text{边}(i,j) \text{ 权值 } c_k xjxick(i,j) 权值 ck

10.2 竞赛技巧宝典
  • 堆优化Dijkstra模板化(必背!)
    using pii = pair<int, int>;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push({0, start});
    
  • SPFA的SLF优化(双端队列骚操作)
    if (!q.empty() && dist[v] < dist[q.front()]) 
        q.push_front(v);
    else
        q.push_back(v);
    
  • Floyd的循环顺序信仰(k-i-j 神圣不可侵犯)
10.3 甘特图:竞赛时间管理
00分 00分 00分 00分 00分 00分 思考 编码 读题 调试 提交 祈祷 自信 怀疑 崩溃 希望 狂喜/绝望 比赛时间 心理状态 ACM竞赛时间管理

🎓 结语:成为路径大师(超扩展版)

记住这些黄金法则:

  1. 正权图 → Dijkstra(堆优化!)
  2. 负权图 → Bellman-Ford/SPFA
  3. 全源最短路 → Floyd(小图)或 Johnson(大图)
  4. 有启发信息 → A* 加速

“最短路径算法就像人生选择——
Dijkstra教我们脚踏实地步步为营
A*告诉我们要有理想导航
Bellman-Ford提醒我们警惕负能量循环
而Floyd启示我们:全局观决定人生高度”

现在,当你在Google Maps规划路线时,不妨想想:此刻正有数百万个Dijkstra实例在为人类服务呢! 🌍💻


终极彩蛋:程序员的最短路径甘特图

07:00 08:00 09:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 起床 咖啡 写代码 最大化编码时间 会议 最小化会议时间 写代码 午餐 写代码 调试 划水 下班 最小化通勤时间 工作流 优化目标 程序员的一天最优路径

路径权重

  • w(床, 咖啡机) = 10min
  • w(咖啡机, 工位) = 5min
  • w(工位, 会议室) = +∞ 😂
  • w(会议室, 工位) = 心理创伤系数100
  • w(工位, 家) = 幸福感+100

(全文终,字数统计:12,587字)

🚀 The Grand Adventure of Shortest Path Algorithms: From Maze Newbie to Graph Theory Ninja (Ultra Extended Edition)

Warning: Reading this article may cause the following side effects: calculating optimal paths when looking at maps, planning food delivery routes with algorithmic thinking, suddenly shouting “This is a negative weight cycle!” during dates. Please bring your own caffeine and fasten your seatbelts—we’re taking off!


🧩 Chapter 1: The Foundations of the Graph Theory Universe (Ultra Extended Edition)

1.1 What is a Graph? (Not the Kind You’re Thinking Of!)

A graph G = (V, E) is a mathematical structure composed of:

  • Vertices (V): Key nodes in the universe, like your ex, current partner, and potential crushes
    V = { v 1 , v 2 , … , v n } V = \{v_1, v_2, \dots, v_n\} V={v1,v2,,vn}
  • Edges (E): Connections between nodes, like the “WeChat delete” edge between you and your ex
    E ⊆ { ( u , v ) ∣ u , v ∈ V } E \subseteq \{ (u,v) \mid u,v \in V \} E{(u,v)u,vV}
Crawl 10min
Sprint 2min
Soul Leaves Body 8hr
Wriggle 1hr
Your Bed
Toilet
Office Time Clock
Off Work
1.2 Weights: The “Cost Metric” of the World

Each edge can carry a weight w: E → ℝ, representing:

  • Distance cost: w(Beijing, Shanghai) = 1200km
  • Time cost: w(Waking Up, Going to Work) = Pain Coefficient 8.5
  • Economic cost: w(Proposal, Marriage) = $$$$...
  • Emotional cost: w(You, First Love) = 1000 Damage Points

Weights can be negative! For example: w(Boss, Raise) = -1000 yuan (because money flows from the boss’s pocket to yours)

[ Bed Toilet Office Off Work Bed 0 10 ∞ ∞ Toilet ∞ 0 2 ∞ Office ∞ ∞ 0 480 Off Work 60 ∞ ∞ 0 ] \begin{bmatrix} & \text{Bed} & \text{Toilet} & \text{Office} & \text{Off Work} \\ \text{Bed} & 0 & 10 & \infty & \infty \\ \text{Toilet} & \infty & 0 & 2 & \infty \\ \text{Office} & \infty & \infty & 0 & 480 \\ \text{Off Work} & 60 & \infty & \infty & 0 \\ \end{bmatrix} BedToiletOfficeOff WorkBed060Toilet100Office20Off Work4800


🚶 Chapter 2: Breadth-First Search (BFS) — The Equal-Opportunity Explorer (Ultra Extended Edition)

2.1 Algorithm Core: Egalitarian Exploration
def BFS(G, start):
    queue = deque([start])          # Initialize queue, enqueue start
    visited = {start: 0}            # Record distance, start at 0
    parent = {start: None}          # Record parent node
    
    while queue:
        u = queue.popleft()         # Dequeue, treat every node equally
        for v in neighbors(u):      # Scan neighbors
            if v not in visited:
                visited[v] = visited[u] + 1  # ⭐Key step! Distance +1
                parent[v] = u       # Record who's the parent
                queue.append(v)
    return visited, parent
2.2 Mathematical Essence: Wavefront Propagation Model

Distance formula:
d ( v ) = min ⁡ u ∈ prev ( v ) { d ( u ) + 1 } d(v) = \min_{u \in \text{prev}(v)} \{ d(u) + 1 \} d(v)=uprev(v)min{d(u)+1}

Gantt Chart: BFS’s Timeline of Conquest

40 seconds 40 seconds Second 0 Second 1 Second 2 Second 3 Start A Node B Node C Node D Node E Node F Goal G Level 0 Level 1 Level 2 Level 3 BFS Conquest Timeline

Real-World Applications:

  • WeChat friend circles (testing the six degrees of separation theory)
  • Virus propagation models (don’t worry, it’s computer viruses!)
  • Finding the nearest toilet (emergency situations!)

⚡ Chapter 3: Dijkstra’s Algorithm — The Cautious Conqueror (Ultra Extended Edition)

3.1 Core Idea: The Perfect Execution of Greedy Strategy

“Always eat the chocolate closest to you until you find a new one that’s even closer”

def Dijkstra(G, start):
    dist = {v: float('inf') for v in G}  # Initialize distances as infinity
    dist[start] = 0
    heap = [(0, start)]                  # Min-heap for speed, stores (distance, node)
    path_tracker = {start: []}           # Path tracker
    
    while heap:
        d_u, u = heapq.heappop(heap)     # Pop the node with the smallest distance
        if d_u != dist[u]: continue      # Skip outdated info (important optimization!)
        
        for v, w in neighbors(u):        # Traverse neighbors
            new_dist = dist[u] + w       # ⭐Relaxation! Try to update distance
            if new_dist < dist[v]:
                dist[v] = new_dist
                path_tracker[v] = path_tracker[u] + [u]  # Update path
                heapq.heappush(heap, (new_dist, v))  # Push to heap
    return dist, path_tracker
3.2 Mathematical Principle: Proof of Optimal Substructure

Relaxation Operation:
δ ( v ) = min ⁡ ( δ ( v ) , δ ( u ) + w ( u , v ) ) \delta(v) = \min \left( \delta(v), \delta(u) + w(u,v) \right) δ(v)=min(δ(v),δ(u)+w(u,v))

Theorem: When all edge weights are non-negative, Dijkstra’s algorithm always finds the shortest path.

Gantt Chart: Dijkstra’s Conquest Schedule

gantt
    title Dijkstra's Conquest Schedule
    dateFormat  ss
    axisFormat %S seconds
    
    section Node Conquest
    Start A : done, a0, 0, 1
    Node B (Distance 2) : active, a1, 1, 2
    Node C (Distance 4) : crit, a2, 2, 3
    Node D (Distance 5) : crit, a3, 3, 4
    Goal E (Distance 7) : milestone, a4, 4, 5
    
    section Heap Operations
    Initial Heap[A:0] : a0, 0, 1
    Pop A, Push B:2, C:4 : a1, 1, 2
    Pop B, Push D:5 : a2, 2, 3
    Pop C, No Update : a3, 3, 4
    Pop D, Push E:7 : a4, 4, 5

Bloody Lesson:
When you try to use Dijkstra to calculate “stock arbitrage paths”—

Negative weights will crash Dijkstra! Because it assumes non-negative weights.


🕵️ Chapter 4: Bellman-Ford Algorithm — The Paranoid Detective (Ultra Extended Edition)

4.1 Algorithm Design: The Beauty of Brute Force
def BellmanFord(G, start):
    dist = {v: float('inf') for v in G}
    dist[start] = 0
    parent = {start: None}
    
    # Phase 1: V-1 rounds of relaxation (V = number of vertices)
    for i in range(len(G)-1):           # ⭐Key loop, V-1 rounds
        updated = False
        for u in G:
            for v, w in neighbors(u):
                if dist[u] + w < dist[v]:
                    dist[v] = dist[u] + w   # Relaxation
                    parent[v] = u
                    updated = True
        if not updated: break  # Early termination optimization
        
    # Phase 2: Detect negative weight cycles
    for u in G:
        for v, w in neighbors(u):
            if dist[u] + w < dist[v]:   # Can still relax?
                raise "Negative weight cycle detected! Path doesn't exist!"
    return dist, parent
4.2 Mathematical Essence: Dynamic Programming Optimization

Path Length Upper Bound Lemma: After k rounds of relaxation, the algorithm finds all shortest paths of length no more than k.

Gantt Chart: Bellman-Ford’s Investigation Progress

gantt
    title Bellman-Ford's Investigation Progress
    dateFormat  ss
    axisFormat %S seconds
    
    section Relaxation Rounds
    Round 1 : a1, 0, 5
    Round 2 : a2, 5, 10
    Round 3 : a3, 10, 15
    ...
    Round V-1 : a4, after a3, 5
    
    section Detection Content
    Direct Neighbors : done, a1, 0, 5
    2-Hop Neighbors : active, a2, 5, 10
    3-Hop Neighbors : crit, a3, 10, 15
    Full Graph Coverage : milestone, a4, 15, 20
    
    section Negative Cycle Detection
    Final Check : crit, after a4, 5

Real-World Mapping:

  • Financial arbitrage detection (negative weight cycle = infinite arbitrage opportunity)
  • Damage boost loops in games (“immortality bug”)
  • Time travel paradox (if you go back in time to kill your grandfather, do you disappear?)

🔥 Chapter 5: SPFA Algorithm — The Social Butterfly Version of Bellman-Ford (Ultra Extended Edition)

5.1 Optimization Idea: Queue-Driven Relaxation
def SPFA(G, start):
    dist = {v: float('inf') for v in G}
    dist[start] = 0
    queue = deque([start])
    in_queue = set([start])             # Avoid duplicate enqueue
    count = {v: 0 for v in G}           # Enqueue counter
    
    while queue:
        u = queue.popleft()
        in_queue.remove(u)
        
        for v, w in neighbors(u):
            new_dist = dist[u] + w
            if new_dist < dist[v]:
                dist[v] = new_dist
                if v not in_queue:      # Only enqueue if not already in queue
                    count[v] += 1
                    if count[v] > len(G):  # Detect negative cycle
                        raise "Negative weight cycle detected!"
                    queue.append(v)
                    in_queue.add(v)
    return dist
5.2 Performance Analysis: Worst Case vs. Average

Gantt Chart: SPFA’s Party Invitation List

40 seconds 40 seconds Initial Queue[A] A Dequeued, Invite B,C B C B Dequeued, Invite D C Dequeued, Invite E D Dequeued, No New Invites E Dequeued, Party Over A D E Queue Status Enqueue Count SPFA's Party Invitation List
ScenarioTime ComplexityPerformance
Sparse GraphO(kE)Flash Speed 🚀
Grid GraphO(VE)Normal Human Speed 👨💻
Poisoned GraphO(VE)Snail Speed 🐌
Negative CyclePerpetual Motion Warning ⚠️

Fun Fact: When SPFA’s inventor Duan Fanding published his paper in 1994, he was probably eating hot pot 🍲


🌌 Chapter 6: Floyd-Warshall Algorithm — The Omniscient God’s Perspective (Ultra Extended Edition)

6.1 The Beauty of Triple-Nested Loops in Dynamic Programming
def FloydWarshall(G):
    n = len(G)
    dist = [[float('inf')] * n for _ in range(n)]
    path = [[None] * n for _ in range(n)]  # Path tracking
    
    # Initialization: Direct neighbors
    for i in range(n):
        dist[i][i] = 0
        for j, w in G[i].items():
            dist[i][j] = w
            path[i][j] = i
            
    # DP Core: k is the intermediate node
    for k in range(n):              # Intermediate node
        for i in range(n):          # Start node
            for j in range(n):      # End node
                if dist[i][k] + dist[k][j] < dist[i][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]  # ⭐Update distance
                    path[i][j] = path[k][j]  # Update path
    return dist, path
6.2 Mathematical Essence: Path Space Decomposition

Define d ( k ) ( i , j ) d^{(k)}(i,j) d(k)(i,j) as the shortest path from i i i to j j j using only nodes { 1 , 2 , . . . , k } \{1,2,...,k\} {1,2,...,k}.

State Transition Equation:
d ( k ) ( i , j ) = min ⁡ ( d ( k − 1 ) ( i , j ) , d ( k − 1 ) ( i , k ) + d ( k − 1 ) ( k , j ) ) d^{(k)}(i,j) = \min \left( d^{(k-1)}(i,j), d^{(k-1)}(i,k) + d^{(k-1)}(k,j) \right) d(k)(i,j)=min(d(k1)(i,j),d(k1)(i,k)+d(k1)(k,j))

Gantt Chart: Floyd’s Universe Construction Plan

gantt
    title Floyd's Universe Construction Plan
    dateFormat  ss
    axisFormat %S seconds
    
    section Intermediate Nodes
    Node 0 : a0, 0, 10
    Node 1 : a1, 10, 20
    Node 2 : a2, 20, 30
    ... 
    Node n-1 : an, after a2, 10
    
    section Knowledge Accumulation
    Direct Connections : done, a0, 0, 10
    1-Hop Paths : active, a1, 10, 20
    2-Hop Paths : crit, a2, 20, 30
    Omniscience : milestone, an, 30, 40

Mind-Blowing Fact:
Running Floyd on a 1000-node graph requires 1 billion loop iterations!
That’s like asking all 7 billion people on Earth to each do 14 additions for you 😱


🎯 Chapter 7: A* Algorithm — The Intelligent Search with GPS (Ultra Extended Edition)

7.1 Heuristic Search: Giving Dijkstra a Navigation System
def A_star(G, start, goal, heuristic):
    open_set = PriorityQueue()
    open_set.put((0, start))
    g_score = {v: float('inf') for v in G}
    g_score[start] = 0
    f_score = {v: float('inf') for v in G}
    f_score[start] = heuristic(start, goal)
    came_from = {}
    
    while not open_set.empty():
        _, current = open_set.get()
        if current == goal:
            return reconstruct_path(came_from, current)
        
        for neighbor, w in neighbors(current):
            tentative_g = g_score[current] + w
            if tentative_g < g_score[neighbor]:
                came_from[neighbor] = current
                g_score[neighbor] = tentative_g
                f_score[neighbor] = tentative_g + heuristic(neighbor, goal)
                if neighbor not in open_set:
                    open_set.put((f_score[neighbor], neighbor))
    return failure
7.2 The Art of Heuristic Function Design

Admissibility:
h ( v ) ≤ actual distance ( v , g o a l ) h(v) \leq \text{actual distance}(v, goal) h(v)actual distance(v,goal)

Consistency:
h ( u ) ≤ w ( u , v ) + h ( v ) h(u) \leq w(u,v) + h(v) h(u)w(u,v)+h(v)

Gantt Chart: A’s Intelligent Navigation*

40 seconds Start A (f=5) Node B (f=5) Node C (f=6) Node D (f=4) Goal (f=0) h(A)=5 h(B)=3 h(C)=2 h(D)=1 h(Goal)=0 Node Exploration Heuristic Function A*'s Intelligent Navigation

Classic Heuristics:

  • Manhattan Distance: h(a,b) = |x₁-x₂| + |y₁-y₂| (only up/down/left/right movement)
  • Euclidean Distance: h(a,b) = √((x₁-x₂)² + (y₁-y₂)²) (straight-line distance)
  • Chebyshev Distance: h(a,b) = max(|x₁-x₂|, |y₁-y₂|) (king’s move, 8 directions)

🏆 Chapter 8: The Algorithm Beauty Pageant (Ultra Extended Edition)

8.1 Scenario Adaptation Guide
AlgorithmBest ScenarioWorst FearPersonality Analysis
BFSUnweighted social graphsWeighted graphsSimple and direct
DijkstraPositive-weight routingNegative weightsCautiously optimistic
Bellman-FordFinancial models with neg. weightsDense graphsParanoid and careful
SPFAFast sparse graph solvingPoisoned input dataOpportunistic
FloydSmall all-pairs shortest pathsLarge graphsJack of all trades but slow
A*Path planning with heuristicsBad heuristicsSmart but GPS-dependent
8.2 Ultimate Complexity Showdown

Algorithm Time Complexity Space Complexity Magic Value BFS O ( V + E ) O ( V ) ✨ Dijkstra O ( ( V + E ) log ⁡ V ) O ( V ) ✨✨ Bellman-Ford O ( V E ) O ( V ) ✨✨✨ SPFA O ( V E ) → O ( k E ) O ( V ) ✨✨✨✨ Floyd-Warshall O ( V 3 ) O ( V 2 ) ✨ A* O ( b d ) O ( b d ) Depends on h \begin{array}{c|c|c|c} \text{Algorithm} & \text{Time Complexity} & \text{Space Complexity} & \text{Magic Value} \\ \hline \text{BFS} & O(V+E) & O(V) & ✨ \\ \text{Dijkstra} & O((V+E)\log V) & O(V) & ✨✨ \\ \text{Bellman-Ford} & O(VE) & O(V) & ✨✨✨ \\ \text{SPFA} & O(VE) \rightarrow O(kE) & O(V) & ✨✨✨✨ \\ \text{Floyd-Warshall} & O(V^3) & O(V^2) & ✨ \\ \text{A*} & O(b^d) & O(b^d) & \text{Depends on h} \\ \end{array} AlgorithmBFSDijkstraBellman-FordSPFAFloyd-WarshallA*Time ComplexityO(V+E)O((V+E)logV)O(VE)O(VE)O(kE)O(V3)O(bd)Space ComplexityO(V)O(V)O(V)O(V)O(V2)O(bd)Magic Value✨✨✨✨✨✨✨✨✨Depends on h

8.3 Gantt Chart: Algorithm Competition Performance
00 seconds 00 seconds 00 seconds 00 seconds 00 seconds 00 seconds Large Graph (5000 nodes) Large Graph Small Graph (50 nodes) Medium Graph (500 nodes) Small Graph Medium Graph Small Graph Medium Graph Large Graph Small Graph Medium Graph Large Graph BFS Dijkstra SPFA Floyd Algorithm Competition Performance Comparison

🚨 Chapter 9: Negative Weight Cycles — The Black Holes of Graph Theory (Ultra Extended Edition)

9.1 Detection Techniques Compared
MethodPrincipleEfficiency
Bellman-FordCan still relax in V-th roundO(VE)
SPFANode enqueue count > VO(VE)
Tarjan’s SCCDetect in strongly connected componentsO(V+E)
9.2 Philosophical Musings on Negative Cycles

“Traversing a negative weight cycle is like loving someone more the more you give—seemingly increasing returns, but actually a death loop”

Mathematical expression:
∃  cycle  C : ∑ e ∈ C w ( e ) < 0 \exists \text{ cycle } C: \sum_{e \in C} w(e) < 0  cycle C:eCw(e)<0

Gantt Chart: The Death Spiral of Negative Cycles

41 seconds Node A→B B→C C→A A→B B→C C→A ... Cycle 1 Cycle 2 Cycle n The Death Spiral of Negative Cycles

🌟 Chapter 10: Practical Training Camp (Ultra Extended Edition)

10.1 Classic Problem Solutions
  1. All-Pairs Shortest Paths
    🔥 Solution: Floyd-Warshall or |V| runs of Dijkstra

  2. K-th Shortest Path
    💡 Solution: Variant of A*, keep searching after finding each path until K paths are found

  3. Difference Constraints System
    ⚙️ Modeling:
    x j − x i ≤ c k ⇒ edge ( i , j )  with weight  c k x_j - x_i \leq c_k \Rightarrow \text{edge}(i,j) \text{ with weight } c_k xjxickedge(i,j) with weight ck

10.2 Competition Tips Handbook
  • Heap-Optimized Dijkstra Template (Must Memorize!)
    using pii = pair<int, int>;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push({0, start});
    
  • SPFA’s SLF Optimization (Double-ended queue trick)
    if (!q.empty() && dist[v] < dist[q.front()]) 
        q.push_front(v);
    else
        q.push_back(v);
    
  • Floyd’s Loop Order Dogma (k-i-j is sacred and inviolable)
10.3 Gantt Chart: Competition Time Management
00 minutes 00 minutes 00 minutes 00 minutes 00 minutes 00 minutes Think Code Read Problems Debug Submit Pray Confident Doubtful Breakdown Hopeful Ecstasy/Despair Competition Time Mental State ACM Competition Time Management

🎓 Conclusion: Becoming a Path Master (Ultra Extended Edition)

Remember these golden rules:

  1. Positive weights → Dijkstra (with heap optimization!)
  2. Negative weights → Bellman-Ford/SPFA
  3. All-pairs shortest paths → Floyd (small graphs) or Johnson (large graphs)
  4. Heuristic information available → A* for acceleration

“Shortest path algorithms are like life choices—
Dijkstra teaches us to advance step by step
A* tells us to navigate with ideals
Bellman-Ford warns us to beware of negative feedback loops
And Floyd enlightens us: the big picture determines life’s altitude”

Now, when you use Google Maps to plan a route, remember: millions of Dijkstra instances are serving humanity at this very moment! 🌍💻


Ultimate Easter Egg: The Programmer’s Shortest Path Gantt Chart

07:00 08:00 09:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 17:00 Wake Up Coffee Write Code Maximize Coding Time Meeting Minimize Meeting Time Write Code Lunch Write Code Debug Slack Off Off Work Minimize Commute Time Workflow Optimization Goals The Programmer's Optimal Daily Path

Path Weights:

  • w(Bed, Coffee Machine) = 10min
  • w(Coffee Machine, Desk) = 5min
  • w(Desk, Meeting Room) = +∞ 😂
  • w(Meeting Room, Desk) = Psychological Trauma Coefficient 100
  • w(Desk, Home) = Happiness +100

(End of article, word count: 12,587)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

༺ཌༀ傲穹_Vortexༀད༻

你的鼓励奖是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值