[英]How can I return all the shortest paths with tied weight using bellman-ford algorithm?
正如标题所说,我正在寻找的是打印按重量捆绑的“所有最短路径”。
例子:
我们有一个图,其边从 0 -> 1 -> 3 开始,权重为 6,但我们也有路径 0 -> 3,权重为 6,下面的算法只返回第一条路径,我会想知道是否有可能同时返回两条或所有路径。 还有一种更有效/更优雅的方式来打印最短路径。 我仅将此代码作为示例,我的代码非常相似,但仅从源代码打印到最后一个顶点。
这里回答了一个类似的问题,但我无法理解代码,因为我熟悉 c++。
#include <iostream>
#include <vector>
#include <iomanip>
#include <climits>
using namespace std;
// Data structure to store graph edges
struct Edge
{
int source, dest, weight;
};
// Recurive Function to print path of given vertex v from source vertex
void printPath(vector<int> const &parent, int v)
{
if (v < 0)
return;
printPath(parent, parent[v]);
cout << v << " ";
}
// Function to run Bellman Ford Algorithm from given source
void BellmanFord(vector<Edge> const &edges, int source, int N)
{
// count number of edges present in the graph
int E = edges.size();
// distance[] and parent[] stores shortest-path (least cost/path)
// information. Initially all vertices except source vertex have
// a weight of infinity and a no parent
vector<int> distance (N, INT_MAX);
distance[source] = 0;
vector<int> parent (N, -1);
int u, v, w, k = N;
// Relaxation step (run V-1 times)
while (--k)
{
for (int j = 0; j < E; j++)
{
// edge from u to v having weight w
u = edges[j].source, v = edges[j].dest;
w = edges[j].weight;
// if the distance to the destination v can be
// shortened by taking the edge u-> v
if (distance[u] != INT_MAX && distance[u] + w < distance[v])
{
// update distance to the new lower value
distance[v] = distance[u] + w;
// set v's parent as u
parent[v] = u;
}
}
}
// Run Relaxation step once more for Nth time to
// check for negative-weight cycles
for (int i = 0; i < E; i++)
{
// edge from u to v having weight w
u = edges[i].source, v = edges[i].dest;
w = edges[i].weight;
// if the distance to the destination u can be
// shortened by taking the edge u-> v
if (distance[u] != INT_MAX && distance[u] + w < distance[v])
{
cout << "Negative Weight Cycle Found!!";
return;
}
}
for (int i = 0; i < N; i++)
{
cout << "Distance of vertex " << i << " from the source is "
<< setw(2) << distance[i] << ". It's path is [ ";
printPath(parent, i); cout << "]" << '\n';
}
}
// main function
int main()
{
// vector of graph edges as per above diagram
vector<Edge> edges =
{
// (x, y, w) -> edge from x to y having weight w
{ 0, 1, 2 }, { 1, 3, 4 }, { 0, 3, 6 }
};
// Set maximum number of nodes in the graph
int N = 5;
// let source be vertex 0
int source = 0;
// run Bellman Ford Algorithm from given source
BellmanFord(edges, source, N);
return 0;
}
更抽象地看这个,你有一些东西可以找到一个最小的东西,你想改变它,让所有其他的东西都同样小。 (在寻找最大的东西时,同样的原则也适用。不过,坚持“最小”有助于更容易解释。)
许多用于寻找极端事物的算法都有一些部分会询问“A 比 B 更极端”。 例如,您可能会看到如下代码:
if ( A < B )
smallest = A;
请注意,它如何忽略关系( A == B
),就像它忽略更糟糕的结果( A > B
)一样。 因此,您只会获得返回的最佳结果中的第一个。 所以这是要改变的。 但是,您不能简单地将A < B
更改为A <= B
,因为在平局的情况下,这会将B
替换为A
,就像在A
是更好的结果时替换它一样。 (您只会得到最后一个返回的最佳结果。)这三种情况(小于、等于和大于)需要分别处理。
要查看的另一个方面是如何跟踪最小的事物。 上面的代码片段表明smallest
与A
具有相同的类型; 这不足以跟踪多个解决方案。 您可能需要一个容器来跟踪解决方案。 vector
可能是一个合理的选择。
把这些放在一起,上面的代码可能会变成下面的样子(在改变了smallest
的声明之后):
if ( A < B ) {
smallest.clear();
smallest.push_back(A);
}
else if ( A == B ) {
smallest.push_back(A);
}
这如何应用于贝尔曼福特?
幸运的是,代码的关键部分相对容易,因为有注释记录它。 更难的部分是更改代码以跟踪多个结果,因为当找到较短的路径时会更新两条数据。 看起来parent
是需要扩展的数据。 这是一个新的声明:
vector< vector<int> > parent (N);
这使用一个空向量而不是-1
来表示“没有父级”。 检查最短路径现在可以变成
if (distance[u] != INT_MAX) {
// if the distance to the destination v can be
// shortened by taking the edge u-> v
if (distance[u] + w < distance[v])
{
// update distance to the new lower value
distance[v] = distance[u] + w;
// forget the previous parent list.
parent[v].clear();
}
// if u-> v is a way to get the shortest
// distance to the destination v.
if (distance[u] + w == distance[v])
{
// add u as a possible parent for v
parent[v].push_back(u);
}
}
这与没有“ else
”的一般方法略有不同。 这是相同的逻辑,只是排列方式有所不同。 请注意,当输入第一个if
子句时,距离向量会更新,因此也会输入第二个if
子句。
我认为处理找到的路径是一个单独的(而不是微不足道的)问题,所以我会让你弄清楚如何更新printPath()
。 不过,我会给出一个版本,在接收新结果的同时保留旧的 output(只是最短路径中的第一条)。 这与其说是一个建议,不如说是一个将新数据结构与旧数据结构联系起来的说明。
// Recursive function to print the path of (just) the first given vertex from source vertex.
void printPath(vector< vector<int> > const &parent, vector<int> const &vlist)
{
if (vlist.empty())
return;
int v = vlist.front();
printPath(parent, parent[v]);
cout << v << " ";
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.