我将Bellman-Ford算法应用于2D阵列时遇到了问题(不是图表)
输入数组具有 m x n 维度:
s[1,1] s[1,2] ... s[1,n] -> Exit
s[2,1] s[2,2] ... s[2,n]
...
Entry -> s[m,1] s[m,2] ... s[m,n]
它是相似的房间(每个条目都是 s [x,y] enterance成本的房间)。每个房间也可能有负成本,我们必须找到最便宜的路径,从进入选择房间到退出。
例如,我们有这样的房间和费用:
1 5 6
2 -3 4
5 2 -8
我们想走过房间 [3,2] , s [3,2] = 4。我们正在开始 5 [1,3] 并且在我们去 [3,3] 之前必须走过 [3,2] 。
我的问题是,在Bellman-Ford算法中实现它的最佳方法是什么?我知道Dijkstry算法不会因负成本而起作用。
从[0,maxHeight]的每个房间是否放松所有邻居?像这样:
for (int i = height-1; i >= 0; --i) {
for (int j = 0; j < width; ++j) {
int x = i;
int y = j;
if (x > 0) // up
Relax(x, y, x - 1, y);
if (y + 1 < width) // right
Relax(x, y, x, y + 1);
if (y > 0) // left
Relax(x, y, x, y - 1);
if (x + 1 < height) // down
Relax(x, y, x + 1, y);
}
}
但是,如何才能读取选择房间以及从房间退出的费用?
答案 0 :(得分:10)
如果您知道如何从数组移动图形,则可以滚动到附加条件段落。另请阅读下一段。
实际上,您可以在图表上查看该建筑物。
那么,如何实施呢?暂时忽略附加条件(离开前访问特定顶点)
体重功能:
让S[][]
成为一个入门成本数组。注意,关于边缘的权重仅决定末端的顶点。它无论是(1, 2) -> (1,3)
还是(2,3) -> (1, 3)
都有。成本由第二个顶点定义。所以功能可能如下:
cost_type cost(vertex v, vertex w) {
return S[w.y][w.x];
}
//As you can see, first argument is unnecessary.
边缘:
实际上,您不必将所有边缘保留在某个数组中。您可以在每次需要时计算它们。
如果节点存在,则顶点(x, y)
的邻居为(x+1, y)
,(x-1, y)
,(x, y+1)
,(x, y-1)
。你必须检查它,但它很容易。 (检查new_x&gt; 0&amp;&amp; new_x&lt; max_x。)它可能看起来像这样:
//Size of matrix is M x N
is_correct(vertex w) {
if(w.y < 1 || w.y > M || w.x < 1 || w.x > N) {
return INCORRECT;
}
return CORRECT;
}
生成邻居可能如下所示:
std::tie(x, y) = std::make_tuple(v.x, v.y);
for(vertex w : {{x+1, y}, {x-1, y}, {x, y+1}, {x, y-1}}) {
if(is_correct(w) == CORRECT) {//CORRECT may be true
relax(v, w);
}
}
我相信,它不应该为四个边缘占用额外的内存。如果你不知道std::tie,请查看cppreference。 (额外变量x
,y
需要更多内存,但我相信它在这里更具可读性。在您的代码中可能不会出现。)
显然你必须有其他具有距离的2D数组和(如有必要)前任,但我认为它很清楚,我不必描述它。
附加条件:
您想知道从进入退出的成本,但您必须访问某些顶点compulsory
。最简单的计算方法是计算从enter
到compulsory
以及从compulsory
到exit
的费用。 (将有两个单独的计算。)它不会改变big O时间。之后,您可以添加结果。
您必须保证在exit
之前无法访问compulsory
。这很容易,你可以通过在is_correct函数中添加额外的行来清除exit
的传出边缘(然后需要顶点v
。)或者生成邻居代码片段。
现在你可以实现它basing on wikipedia。你有图表。
为什么你不应该听?
更好的方法是从其他顶点使用Belman Ford算法。请注意,如果您知道从A到B的最佳路径,您还知道从B到A的最佳路径。为什么?总是你必须支付最后一个顶点并且你不需要先付费,所以你可以忽略它们的成本。休息很明显。
现在,如果您知道您想要知道路径A-> B和B-> C,则可以使用来自节点B的一次BF和反向路径B来计算B-> A和B-> C. ;一个。结束了。
您只需要清除entry
和exit
节点的传出边缘。
但是,如果您需要非常快速的算法,则必须对其进行优化。但我认为这是另一个话题。此外,似乎没有人对硬优化感兴趣
我可以快速添加,只是那个小而简单的优化基础,你可以忽略相应的遥远顶点的放松。在数组中,您可以轻松地计算距离,因此它是令人愉快的优化。
我没有提到很好的优化,因为我相信所有这些都是在网络的随机过程中。