📅  最后修改于: 2023-12-03 15:07:02.845000             🧑  作者: Mango
允许两种不同的操作,从 0 到 N 点的最小成本
在许多算法问题中,我们需要在一个图或网格中找到最小成本的路径或通路。 本文将介绍两种常见的最小成本路径问题:最短路径和最小生成树。
一、最短路径
1. Dijkstra算法
Dijkstra算法用于解决带权有向图中单源点到所有其他点的最短路径问题。
算法步骤如下:
- 创建一个包含源点的集合S和一个不包含源点的集合T。
- 初始化距离数组dist,源点距自己的距离为0,其余点距离源点无穷大。
- 从未标记的点中选择一个最小距离的点u,将其标记为已访问。
- 对于u的每个邻居v,更新其距离:如果从源点到u的距离再加上u到v的距离小于原有的距离,则更新距离。
- 重复步骤3和4,直到所有点都被访问过或不存在未标记点到源点的路径。
Dijkstra算法的时间复杂度为$O(n^2)$, 如果使用堆等数据结构可优化到$O(nlogn)$。
2. Bellman-Ford算法
Bellman-Ford算法解决带权有向图中单源点到所有其他点的最短路径问题,但它可以处理存在负权边的情况。
算法步骤如下:
- 初始化距离数组dist,源点距自己的距离为0,其余点距离源点无穷大。
- 对于每条边(u, v, w),将dist[v]更新为min(dist[v], dist[u] + w)。
- 重复步骤2,直到没有任何点的距离被更新。
Bellman-Ford算法总共需要执行$O(nm)$次更新,时间复杂度为$O(nm)$。
3. Floyd算法
Floyd算法用于解决图中所有点对之间的最短路径问题。
算法步骤如下:
- 初始化一个n*n的二维数组dist,将每对连通点之间的距离设置为其边的权值,如果不存在,则设置为无穷大。
- 对于每个顶点k,从i到j的距离为min(dist[i][j], dist[i][k]+dist[k][j])。
- 重复执行步骤2,直到所有顶点的距离都被更新。
Floyd算法的时间复杂度为$O(n^3)$。
二、最小生成树
最小生成树是指在一个带权连通图中,找到一棵生成树,使得其所有边的权值之和最小。
1. Kruskal算法
Kruskal算法用于解决无向带权连通图的最小生成树问题。
算法步骤如下:
- 初始化包含所有节点、但没有边的森林。
- 将所以边按权值从小到大排序。
- 依次取出每条边,如果该边所连接的两个点在同一个树中,则舍弃该边;否则将其加入生成树中并将所在的两棵树合并为一棵树。
- 重复执行步骤3,直到森林成为一棵树。
Kruskal算法的时间复杂度为$O(mlogm)$。
2. Prim算法
Prim算法用于解决无向带权连通图的最小生成树问题。
算法步骤如下:
- 初始化一个新的集合U,其中包含一个起点。
- 初始化一个新的距离数组dist,其中距离d[i]表示从U中最近的顶点到顶点i的距离,起点的距离d[s]为0,其余为无穷大。
- 每次将距离dist最小的那个点加入U,然后更新dist数组。
- 重复执行步骤3,直到所有点都被加入U。
Prim算法的时间复杂度为$O(n^2)$。
总结
在算法问题中,求解最小成本的路径或通路是最为经典的问题之一。本文介绍了两种最小成本路径问题(最短路径和最小生成树),其中分别介绍了三种求解方法。在实际应用中,我们需要根据具体问题的情况选择最适合的算法。