C++ 实现Bellman-Ford算法C++;

C++ 实现Bellman-Ford算法C++;,c++,C++,我目前正在做一个家庭作业来实现贝尔曼-福特算法。到目前为止,我已设法读入提供的图形,将其放入一个向量(使用1d向量表示具有行主顺序的2d向量)中用作矩阵。我使用一个结构来跟踪边的权重,一个布尔值来判断它是否无穷大(不存在边),一个变量来跟踪前面的节点 我遇到的难题是如何实现dang算法。我已经从中阅读了伪代码,但我很难掌握如何使用该算法。前80行读取文件,初始化向量,将值扔到向量的正确位置。下面是我开始为算法实现的内容。我确实有几个具体问题 1) 在我找到的所有关于算法的解释中,你使用了节点的算

我目前正在做一个家庭作业来实现贝尔曼-福特算法。到目前为止,我已设法读入提供的图形,将其放入一个向量(使用1d向量表示具有行主顺序的2d向量)中用作矩阵。我使用一个结构来跟踪边的权重,一个布尔值来判断它是否无穷大(不存在边),一个变量来跟踪前面的节点

我遇到的难题是如何实现dang算法。我已经从中阅读了伪代码,但我很难掌握如何使用该算法。前80行读取文件,初始化向量,将值扔到向量的正确位置。下面是我开始为算法实现的内容。我确实有几个具体问题

1) 在我找到的所有关于算法的解释中,你使用了节点的算法-1次。在我看过的一些实现中,我倾向于从1开始。为什么会这样?此外,在我的实现中,这仍然有意义吗

2) 在维基百科的伪代码中,它说要检查每个边u,v,u是起始顶点,v是结束顶点。在我的矩阵中,据我所知,这意味着我需要检查每行、每列对的权重/值,看看是否有更好的路径。我不确定我是否正确地解释了这一点,甚至不知道我是否理解了这一点。如有任何建议/指导/提示/演示,将不胜感激。下面是粘贴讲师演示输入的源代码

#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

struct graphNode
{
    int value; //Weight of the edge
    bool isInfinity; //Boolean to flag an edge as infinity
    int pred; //predecessor node
};

// Code for reading inputfile cribbed and modified from http://stackoverflow.com/questions/7651243/c-read-a-file-name-from-the-command-line-and-utilize-it-in-my-file
int main(int argc, char** argv) 
{
    ifstream input; // ifstream for the input
    string inFile = ""; //name of the input file
    int row; //Variable to keep track of what row we're inputting data for
    int col; //Variable to keep track of a column thingie, expand on this later
    int infinity = 99999999;
    int nodeCount; //Number of nodes from input file
    int edgeCount = 0; //Number of edges from the input file

    vector<graphNode> edgeList; //2D list of edges, order is a->b
    edgeList.push_back(graphNode());
    edgeList[0].value = 0;
    edgeList[0].isInfinity = false;
    edgeList[0].pred = -1;

    if( argc == 2 ) 
    {
        inFile = argv[1];
    }
    else 
    {
        cout << "Usage: ./a.out inputFile\n";
        return 1;
    }

    input.open(inFile.c_str()); // opening the provided file

    if(input.is_open()) // making sure the input is open
    {
        input >> nodeCount; //Grabbing the number of nodes from the first value of the file

        for(int i = 1; i < nodeCount*nodeCount; i++)
        {
            edgeList.push_back(graphNode());
            edgeList[i].value = infinity;
            edgeList[i].isInfinity = true;
            edgeList[i].pred = -1;
        }

        //Putting data from the file into the vector array
        while(!input.eof())
        {
            input >> row; //For each cycle through the list, we grab the first number on the line to get which x value (start vertex) we're working with
            while(input.peek() != '\n' && input.peek() != '\r' && !input.eof())
            {
                input >> col;
                input >> edgeList[((row-1)*nodeCount)+(col-1)].value;
                edgeList[((row-1)*nodeCount)+(col-1)].isInfinity = false;
                edgeList[((row-1)*nodeCount)+(col-1)].pred = row;
                edgeCount++;
            }

        }
        input.close(); //Closing our input file since we don't need it anymore
    }
    else
    {
        cout << "Error, something happened with the input." << endl;
        return 1;
    }

    //for(int i = 0; i < nodeCount - 1; i++)
    //{
        //for(int r = 0; r < nodeCount - 1; r++)
        //{
            //for(int c = 0; r < nodeCount - 1; c++)
            //{
                //if(r == c) continue;
                //if(edgeList[r][c].isInfinity) continue;
                //if(edgeList[i][r] + edgeList[r][c] < edgeList[c][i])
}
对于#1,您正在检查节点之间的边,以便最长路径不能超过nodeCount-1边。例如,如果nodeCount==1,则无需检查任何边

对于#2,您有有趣的数据结构。看来你需要不同的。您的“graphNode”应该称为“graphEdge”,但不包含“pred”变量。声明两个新结构:

vector<int> predecessor;
vector<int> distance;
向量前置;
矢量距离;
每个都是nodeCount大小。你在维基百科上看到的“w”是你的边缘主义者

在您注释掉的最后一节中,外部循环正在迭代nodeCount次。它应该是nodeCount-1,但没有害处。然而,由于你有一个一维的边列表,你将其视为二维的,所以你以后的索引是关闭的。您可以通过edgeList[(r-1)*nodeCount+c]访问正确的边


不确定这是否算是一个答案,但这只是一个开始。

在这里查看有关贝尔曼-福特算法的短片。我认为这可能有助于您更好地理解算法:

基本上,贝尔曼福特背后的主要理念是:

要在2个节点(例如s和t)之间找到最短路径,您需要迭代地找到从s到t的最短路径,并且在每个后续迭代中,允许算法在路径中使用比上一次迭代多1条边

在任何特定的迭代k中,现在允许算法在路径中最多使用k条边,s和t之间的最短路径可以是

  • 通过精确地使用k边或
  • 取与该值相同的值 从上一次迭代中发现,即使用a最多(k-1)条边
  • 因此,在特定迭代k中:

    设d[k][t]是从s到节点t的距离,最多使用k条边。然后:

    d[ k ][ t ] = min{ 
    d[k - 1][ t ], # Case 2
    for all edges (u, t) in graph min d[k - 1][ u ] + c[ u ][ t ] # Case 1
    }
    
    其中,上面的min{,.}方程的第二部分简单地查找s到最终目的地t的任何相邻u之间的最短路径,并添加从u到t的边c[u][t]的代价,从而要求精确地
    k条边

    因此,伪代码如下所示:

    d[s][0] = 0 # The cost from s to itself requiring zero edges is 0.
    d[u][0] = INFINITY for all other nodes other than s (i.e. you cannot reach them with no edges).
    
    Let n = number of nodes in graph
    for k = 1 to n - 1: # Allow one more edge in path in each iteration
      for every edge (u, v) in edges of graph: # Check whether can get a better cost to v using k edges by going through node u or k - 1 edges is enough.
        d[ v ][ k ] = min{ d[k - 1][ v ], d[k - 1][ u ] + c[ u ][ v ] }
    

    回答你的问题的第1部分,考虑方程的外环在边数上循环。它从1增加到n-1,其中n是图中的节点数。达到n-1的原因是路径中可以拥有的最大边数是(n-1)条边(即,最终连接所有n个节点以从s到t,它们之间有n-1条边)

    回答您的问题的第2部分,您只需要考虑每个目的节点的传入节点,并检查是否使用k - 1边的一个节点的路径加上从该节点到目的节点的成本比以前低,如上面所解释的。 最后,为了检查负循环(wiki代码的最后一部分),您需要再运行一次算法。我们知道,任何路径最多可以使用n-1条边。任何更多的都是多余的。因此,如果允许再使用1条边,则任何路径的成本都会降低,那么它一定包含了一个负循环,因为这是降低成本的唯一方法。任何非负循环都会导致与使用更多边缘相同或更高的成本


    我郑重推荐您在上面的链接中观看Tim Rawgarden的视频。请注意,他的处理方式与wikipedia中的伪代码略有不同,但基本上是相同的。

    只是稍微相关:将此:
    while(!input.eof())
    更改为此
    while(input>>行)
    ,并立即在循环中删除提取。同样,您也可以使用
    std::getline()
    和中间
    istringstream
    对每行的处理循环进行优化,使其更加干净。这里有一个指向我的Python实现的链接,可能会有所帮助:
    d[s][0] = 0 # The cost from s to itself requiring zero edges is 0.
    d[u][0] = INFINITY for all other nodes other than s (i.e. you cannot reach them with no edges).
    
    Let n = number of nodes in graph
    for k = 1 to n - 1: # Allow one more edge in path in each iteration
      for every edge (u, v) in edges of graph: # Check whether can get a better cost to v using k edges by going through node u or k - 1 edges is enough.
        d[ v ][ k ] = min{ d[k - 1][ v ], d[k - 1][ u ] + c[ u ][ v ] }