从最短路径到最小生成树,理解 Dijkstra、Prim、Kruskal 和阿克曼函数

📌 前言

今天学习了贪心算法的Dijkstra和最小生成树的Prim、Kruskal,数据结构图、矩阵、最小堆,以及阿克曼函数等:

  • Dijkstra 算法(单源最短路径)
  • Prim 和 Kruskal 算法(最小生成树)
  • 最小堆(优化路径搜索)
  • 阿克曼函数与反阿克曼函数(超快增长的数学函数)
  • 图的存储方式(邻接矩阵 vs 邻接表)
  • 三对角矩阵(数值计算优化)

1️⃣ Dijkstra 算法:找最短路径的"导航系统"

❓ 问题:如何从A点走到B点,路程最短?

想象你开车在城市中导航,Google Maps 需要计算 最短路径 。Dijkstra 算法就像一个聪明的导航助手,帮你找到 从起点到终点的最短路径

🎯 Dijkstra 的核心思路

  1. 先假设所有路径都很远,起点到自身的距离为 0,其他点距离是无穷大。
  2. 每次选择当前最短的路径,进行扩展(贪心策略)。
  3. 用最小堆加速选择最优路径(不然太慢)。
  4. 重复这个过程,直到到达终点

📝 代码框架

python 复制代码
import heapq  # Python 自带的最小堆

def dijkstra(graph, start):
    dist = {node: float('inf') for node in graph}
    dist[start] = 0
    pq = [(0, start)]  # (当前距离, 当前节点)

    while pq:
        d, node = heapq.heappop(pq)  # 取出当前最短路径的点

        for neighbor, weight in graph[node]:
            new_dist = d + weight
            if new_dist < dist[neighbor]:
                dist[neighbor] = new_dist
                heapq.heappush(pq, (new_dist, neighbor))

    return dist

💡 Dijkstra 适用于最短路径问题(导航、网络路由、AI 路径规划)。


2️⃣ Prim 和 Kruskal:如何用最少的电线连通整个城市?

❓ 问题:假设你是城市规划师,要用最少的电缆连接所有的建筑物,怎么办?

这就是 最小生成树(MST) 的问题,解决方案有两种:

  • Prim 算法(每次扩展最短的边,像"长城"一样慢慢扩展)
  • Kruskal 算法(按照边长排序,像"修桥"一样连接两座城市)

🚀 Prim 算法(适用于稠密图)

💡 思路

  1. 从某个点开始,每次选最短的边,扩展新点(像建长城)。
  2. 不断扩展,直到所有点都被连通

📝 代码框架(最小堆优化)

python 复制代码
import heapq

def prim(graph, start):
    mst_cost = 0
    visited = set()
    pq = [(0, start)]  # (权重, 节点)

    while pq:
        weight, node = heapq.heappop(pq)
        if node in visited:
            continue
        visited.add(node)
        mst_cost += weight

        for neighbor, edge_weight in graph[node]:
            if neighbor not in visited:
                heapq.heappush(pq, (edge_weight, neighbor))

    return mst_cost

Prim 适合 边多的稠密图(Dense Graph) ,因为它每次只选最短的边,不需要排序所有边


🚀 Kruskal 算法(适用于稀疏图)

💡 思路

  1. 把所有的边按照长度排序(像修桥)。
  2. 从最短的开始连接,只要不会成环,就加入(用"并查集"管理)。
  3. 直到所有点都连通

📝 代码框架(并查集优化)

python 复制代码
class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])  # 路径压缩
        return self.parent[x]

    def union(self, x, y):
        rootX, rootY = self.find(x), self.find(y)
        if rootX != rootY:
            self.parent[rootY] = rootX

def kruskal(edges, n):
    uf = UnionFind(n)
    mst_cost = 0
    edges.sort(key=lambda x: x[2])  # 按边长排序

    for u, v, weight in edges:
        if uf.find(u) != uf.find(v):  # 确保不会成环
            uf.union(u, v)
            mst_cost += weight

    return mst_cost

Kruskal 适合 边少的稀疏图(Sparse Graph) ,因为它 先排序,再连边,不需要检查所有点。


3️⃣ 阿克曼函数:增长速度比指数还恐怖!

阿克曼函数是一种增长超级快的递归函数:

python 复制代码
def ackermann(m, n):
    if m == 0:
        return n + 1
    if n == 0:
        return ackermann(m - 1, 1)
    return ackermann(m - 1, ackermann(m, n - 1))

如果你输入:

python 复制代码
print(ackermann(3, 4))  # 结果是125

ackermann(4, 2) 就能让你的电脑死机!

💡 反阿克曼函数(Inverse Ackermann Function)在 并查集优化 中至关重要,它让并查集的查询几乎变成 O(1) 级别 的操作!


4️⃣ 图的存储方式:邻接矩阵 vs 邻接表

💡 图可以用两种方式存储

存储方式 适用场景 优势 缺点
邻接矩阵 稠密图 O(1) 查询边 O(V²) 空间浪费
邻接表 稀疏图 O(V+E) 存储更省 O(V) 查找某条边

结论

  • 如果边很多(稠密图),用邻接矩阵
  • 如果边少(稀疏图),用邻接表

🎯 总结

Dijkstra :最短路径问题,适用于导航、AI、网络优化。

Prim :最小生成树(MST),适合 边多的稠密图

Kruskal :最小生成树(MST),适合 边少的稀疏图

阿克曼函数 :增长极快,反阿克曼函数优化 并查集

图的存储方式:邻接矩阵(适合边多),邻接表(适合边少)。

📌 一句话总结:Dijkstra 负责找路,Prim & Kruskal 负责连线,阿克曼函数是数学怪兽!🔥

相关推荐
Jerry18 分钟前
LeetCode 101. 对称二叉树
算法
可编程芯片开发1 小时前
基于MPPT最大功率跟踪的离网光伏发电系统Simulink建模与仿真
算法
AI科技星2 小时前
线性算子不是空间映射函数,是全域双螺旋场之间拉伸、旋转、耦合、坍缩的跨空间标准化变换载体《全域数学vs传统数学:人类文明进阶200讲》第80讲
线性代数·算法·矩阵·数据挖掘·回归·乖乖数学·全域数学
米罗篮2 小时前
矩阵快速幂 (Exponentiation By Squaring Applied To Matrices)
c++·线性代数·算法·矩阵
dream_home84072 小时前
图像算法模型NPU适配与算法服务实战指南
人工智能·python·算法·npu 图像服务
大鱼>2 小时前
多宠物家庭智能管理平台:云端架构与多设备协同实战
python·算法·iot·宠物
To_OC3 小时前
LC 22 括号生成:刷完这道题,我终于搞懂回溯剪枝了
javascript·算法·leetcode
To_OC3 小时前
LC 39 组合总和:回溯入门必刷题,我踩过的两个坑都在这了
javascript·算法·leetcode
数字杂技师3 小时前
每条推荐都很准,为什么我还是越刷越无聊?
算法
兰令水3 小时前
hot100【acm版】【2026.7.14打卡-java版本】
java·数据结构·算法·leetcode·面试