我一直在尝试通过遵循以下资源来理解Bellman-Ford的正确实现:1和2
如果我们已经知道给定的加权有向图不包含循环(因此也没有负循环),是否遵循Bellman-Ford算法的正确实现?
int src = 0;
int V = nodes.length; // 0 to n-1 nodes
int E = edges.length;
double[] distTo = new double[V];
for (int i = 0; i < V; i++) {
distTo[i] = Double.POSITIVE_INFINITY;
}
int[] edgeTo = new int[V];
distTo[src] = 0.0;
for (int i = 1; i < V - 1; i++) {
double[] distToLocal = new double[V];
for (int j = 0; j < V; j++) {
distToLocal[j] = Double.POSITIVE_INFINITY;
}
for (int j = 0; j < E; j++) {
int to = edges[i].to;
int from = edges[i].from;
int weight = edges[i].weight;
if (distToLocal[to] > distTo[to] && distToLocal[to] > distTo[from] + weight) {
distToLocal[to] = distTo[from] + weight;
edgeTo[to] = from;
}
distToLocal[to] = Math.min(distToLocal[to],distTo[to]);
}
distTo = distToLocal;
}
上述实现的第一个问题是,如果图中只有2个节点,且从源节点到目标节点的方向都是有向边的,则需要将第一个for
循环修改为从0
而不是1
开始,如下所示:
for (int i = 0; i < V - 1; i++) {
如果进行上述更改,它仍然是正确的实现吗?
实施中的变化
如果没有必要从src
到具有K个最大边缘(其中K为[0,V-1])的节点到int src = 0;
int V = nodes.length; // 0 to n-1 nodes
int E = edges.length;
double[] distTo = new double[V];
for (int i = 0; i < V; i++) {
distTo[i] = Double.POSITIVE_INFINITY;
}
int[] edgeTo = new int[V];
distTo[src] = 0.0;
for (int i = 1; i < V - 1; i++) {
/*double[] distToLocal = new double[V];
for (int j = 0; j < V; j++) {
distToLocal[j] = Double.POSITIVE_INFINITY;
}*/
for (int j = 0; j < E; j++) {
int to = edges[i].to;
int from = edges[i].from;
int weight = edges[i].weight;
if (distTo[to] > distTo[from] + weight) {
distTo[to] = distTo[from] + weight;
edgeTo[to] = from;
}
}
//distTo = distToLocal;
}
的最短距离,那么以下变化似乎也可以给出正确的结果。
struct foo {
using Func = std::function<void(Args...)>;
foo(const Func& func, Args... args) { ... }
struct none {};
using A = typename std::conditional<sizeof...(Args) > 0, Func, none>::type;
foo(const A& func) { ... };
我想我理解为什么变体有效,但是我很好奇为什么资源1没有提到这一点。
实施此变体是否有不利之处?显然,这些变体具有更好的内存需求。
注意:我知道当加权有向图中没有循环时,可以使用拓扑排序SPT算法,但是我试图理解Bellman-Ford的正确性。
答案 0 :(得分:0)
Bellman-Ford算法指出,在V-1阶段,每个边缘的松弛阶段将计算出源到任何目标之间的最小距离。在您的实现中,您将运行每个阶段的V-2迭代。实际上,两个实现是相同的,您可以重用旧的距离数组。