DAG(有向无环图)、Dijkstra算法和Bellman-Ford算法都是在图论中的重要算法。本文将简单介绍三者原理、彼此异同,以及各自的应用场景。
1.DAG(有向无环图)
1.1原理
- 通过特定方法对有向无环图进行拓扑排序,确定顶点的线性顺序,使每条边的起始顶点排在终点顶点之前。
- 依拓扑排序的顶点顺序,处理每个顶点,对其出边连接的顶点进行松弛,若经当前顶点到邻接顶点的路径更短就更新距离
- 完成拓扑排序与松弛操作后,确定源点到各顶点的最短路径长度,因按拓扑顺序处理,保证了算法正确。
1.2应用
- 项目管理:在项目进度规划中,任务之间的依赖关系可以用有向无环图表示。通过该算法可以确定项目从开始到每个任务完成的最短时间,从而优化项目执行计划。
- 课程安排:在大学课程规划中,课程之间的先修关系构成有向无环图。利用此算法可以找到完成所有课程的最短时间路径,合理安排学习顺序。
- 生产流程优化:在工业生产中,各个生产环节的先后顺序可表示为有向无环图。该算法能确定从原材料到成品的最短生产时间路径,提高生产效率。
下面是关于简单模拟课程安排应用的python代码:
from collections import defaultdict
# 定义有向无环图
graph = defaultdict(list)
graph[0].append((1, 3)) # 课程 0 到课程 1 需要 3 个时间单位
graph[0].append((2, 2)) # 课程 0 到课程 2 需要 2 个时间单位
graph[1].append((3, 4)) # 课程 1 到课程 3 需要 4 个时间单位
graph[2].append((3, 1)) # 课程 2 到课程 3 需要 1 个时间单位
# 初始化距离数组和入度数组
num_courses = 4
distances = [float('inf')] * num_courses
distances[0] = 0
in_degrees = [0] * num_courses
for course in graph:
for neighbor, weight in graph[course]:
in_degrees[neighbor] += 1
# 拓扑排序并更新距离
queue = [course for course in range(num_courses) if in_degrees[course] == 0]
while queue:
current_course = queue.pop(0)
for neighbor, weight in graph[current_course]:
distances[neighbor] = min(distances[neighbor], distances[current_course] + weight)
in_degrees[neighbor] -= 1
if in_degrees[neighbor] == 0:
queue.append(neighbor)
print(distances[3]) # 输出完成所有课程的最短时间
2.Dijkstra (迪杰斯特拉)
2.1原理
- 初始化:设源点为s,dist[0]=0,其他顶点距离设为无穷大,S为空集(S表示确定最短距离的顶点集)。
- 选择顶点:从不在S中的顶点选距离源点最近的顶点u,将u加入S。
- 松弛操作:对u的邻接顶点v,若dist[u] + w(u,v)< distv[v]是边(u,v)权重),则更新dist[v]。
- 重复:不断重复上述步骤,直到所有顶点都在S中,此时dist存储源点到各顶点的最短路径长度。
2.2应用
- 地图导航:用于计算两点之间的最短路径,为出行者规划最佳路线
- 物流配送:确定网络中数据传输的最短路径,提高传输效率
- 网络路由 :规划配送路线,使货物以最短时间送达目的地。
下面是关于模拟简单物流配送应用的python代码:
import heapq
def dijkstra(graph, start):
distances = {node: float('infinity') for node in graph}
distances[start] = 0
priority_queue = [(0, start)]
while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)
if current_distance > distances[current_node]:
continue
for neighbor, weight in graph[current_node].items():
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
# 示例图表示
graph = {
'A': {'B': 1, 'C': 4},
'B': {'A': 1, 'C': 2, 'D': 5},
'C': {'A': 4, 'B': 2, 'D': 1},
'D': {'B': 5, 'C': 1}
}
start_node = 'A'
distances = dijkstra(graph, start_node)
print("最短距离:", distances)
3.Bellmen-Ford
Belman-ford 算法是一种用于求解图中某一特定顶点到其他各顶点的最短路径的算法,尤其适用于存在负权边的图。
3.1原理
-
初始化:设源点为 s。初始化一个距离数组 dist,将源点到自身的距离 dist [s]设为 0,到其他所有顶点的距离设为无穷大。
-
松弛操作:对图中的所有边进行松弛操作。对于每条边(u,v),如果 dist [u]+w (u,v)<dist [0](其中 w (u,v) 表示边0(u,v)的权重),则更新 dist [v]=dist [u]+w (u,v)。重复这个过程 V-1 次(V 是图中顶点的数量)。
-
检测负权回路:在进行了 V-1 次松弛操作后,如果还能进行松弛操作,说明图中存在负权回路例如,在经济模型中,如果某些交易路径存在负权边(例如成本为负),Bellman-ford 算法可以用来确定最优的交易策略路径。
3.2应用
- 网络路由:在网络中,如果存在某些链路的成本为负(例如促销活动导致数据传输费用降低),Bellman-Ford 算法可以用来确定数据包从源节点到其他各节点的最佳路径。
- 经济模块:在经济决策中,如果某些交易或投资活动具有负成本(例如补贴、返利等情况),可以使用该算法找到最优的交易路径,以实现最大收益或最小成本。
- 动态规划问题求解 :某些动态规划问题可以转化为图的最短路径问题,当图中可能存在负权边时,Bellman-Ford 算法可以派上用场。例如,在资源分配问题中,如果某些资源的转移会带来负收益,该算法可以确定最优的资源分配方案
下面是关于模拟简单动态规划问题应用的python代码:
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = []
def add_edge(self, u, v, w):
self.graph.append((u, v, w))
def bellman_ford(self, source):
distances = [float('inf')] * self.V
distances[source] = 0
for _ in range(self.V - 1):
for u, v, w in self.graph:
if distances[u]!= float('inf') and distances[u] + w < distances[v]:
distances[v] = distances[u] + w
for u, v, w in self.graph:
if distances[u]!= float('inf') and distances[u] + w < distances[v]:
return "图中存在负权回路"
return distances
# 创建图
g = Graph(5)
g.add_edge(0, 1, -1)
g.add_edge(0, 2, 4)
g.add_edge(1, 2, 3)
g.add_edge(1, 3, 2)
g.add_edge(1, 4, 2)
g.add_edge(3, 2, 5)
g.add_edge(3, 1, 1)
g.add_edge(4, 3, -3)
source = 0
print(g.bellman_ford(source))
4.DAG、Dijkstra、Bellmen-Ford的异同
相同点:
- 目的都是求解图中顶点之间的最短路径问题。
不同点:
- 适用范围:Dijkstra 算法不能处理负权边,而 Bellman-Ford 算法可以处理负权边;DAG 算法适用于有向无环图。
- 算法思想:Dijkstra 算法通过贪心策略选择距离源点最近的未确定顶点进行扩展;Bellman-Ford 算法通过多次对所有边进行松弛操作来确定最短路径;DAG 算法利用拓扑排序和松弛操作求解。
- 时间复杂度:在稀疏图中,Bellman-Ford 算法和 Dijkstra 算法的时间复杂度相近,但在稠密图中,Dijkstra 算法通常比 Bellman-Ford 算法更快;DAG 算法的时间复杂度与图的拓扑排序和边的数量有关。
综上所述,异同如下表。
| 比较项目 | DAG | Dijkstra | Bellman-Ford |
|---|---|---|---|
| 适用范围 | 有向无环图 | 不能处理负权边的有向图 | 可处理负权边的有向图 |
| 算法思想 | 利用拓扑排序和松弛操作求解 | 贪心策略选择距离源点最近的未确定顶点进行扩展 | 多次对所有边进行松弛操作确定最短路径 |
| 时间复杂度 | 与图的拓扑排序和边的数量有关 | 对于稀疏图通常较快,时间复杂度一般为 O ((V+E) logV),其中 V 是顶点数,E 是边数 | O (VE),V 是顶点数,E 是边数 |
| 能否确定负权回路 | 不能 | 不能 | 能确定图中是否存在负权回路 |
2427

被折叠的 条评论
为什么被折叠?



