【发布时间】:2019-07-14 20:27:59
【问题描述】:
我一直在尝试通过以下资源了解 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 为 [0,V-1] 的最大 K 条边,那么以下变化似乎也能给出正确的结果。
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;
}
我想我理解为什么变体有效,但是我很好奇为什么资源 1 没有提到这一点。
实施这种变体有什么缺点吗?显然,该变体具有更好的内存要求。
注意:我知道当加权有向图中没有环时我可以使用拓扑排序 SPT 算法,但我试图理解 Bellman-Ford 的正确性。
【问题讨论】:
标签: java graph-theory bellman-ford