问题描述
我有一个带有一些边的图。每条边都有一个权重/成本以及一个标签/类型,可以是 red
和 green
。
我知道,如果我运行 Dijkstra 算法,它将从所有边的权重中找到最短/最便宜的路径。但是,我的问题是,根据它选择的边缘类型,应该增加额外的成本。原则上,每次使用新类型时才应增加额外成本。
例如,如果我从 Dijkstra's 找到的路径是:
node1 ---> node2 ---> node3 ---> node4 -----> node5 -----> node6
|---- edge1 --|-- edge2 ---|--- edge3 --|--- edge4 ----|--- edge5 ----|
type = red type = red type = red type = green type = green
for i,edge in enumerate(path.edges):
if edge[i].type == edge[i+1].type:
<do not add any additional cost>
elif edge[i].type != edge[i+1].type:
<add additional cost to [i] edge>
因此,仅当路径内的类型发生变化时才应增加额外成本。
我不知道这是否可以以任何方式实现?
解决方法
您可以将 Dijkstra 算法应用于图形的修改版本,这将考虑额外成本:
- 复制图中的每个节点,使旧图中的每个节点
v
对应新图中的一个绿色节点v_g
和一个红色节点v_r
; - 新节点
v_g
将从v
获取每条绿色边; - 新节点
v_r
将从v
获取每条红色边; - 此外,添加一条连接
v_g
到v_r
的边,权重为<add additional cost to [i] edge>
。
另一种思考这种结构的方式是想象你有原始图的两个副本:红色图和绿色图;两个图都有所有的节点,但每个图只有正确颜色的边;并且有一条额外的黑边将红色图中的每个节点连接到绿色图中的相应节点。
路径的起点: 路径开始的节点在 Dijkstra 算法中扮演着特殊的角色。既然开始节点现在已经分成了两个节点start_r
和start_g
,那么你怎么知道从哪个节点开始Dijkstra呢?您可以运行该算法两次,一次来自 start_g
,一次来自 start_r
,并保留最小的解决方案;但有一个更好的解决方案。由于最短路径将没有环,您可以将start_r
和start_g
之间的边上的权重设置为0,而不是其他节点的权重;最短路径不会使用这条边,除非可能有一次作为路径的第一条边。
请注意,结束节点在 Dijkstra 算法中没有任何特殊作用(Dijkstra 实际上计算从开始节点到其他每个节点的最短距离);所以你不需要担心终端节点。
现在您可以在新图上运行常规 Dijkstra 算法。