当前位置: 首页 > 知识库问答 >
问题:

贝尔曼-福特图算法

江德润
2023-03-14

我有一个家庭作业来实现贝尔曼·福特的算法,并在一些图形上测试它。我实现了这个算法,在3张图中的2张上测试了它,它是有效的。但是在第三个图中,我在调用函数时没有输出。

Graph* temaTrecuta = createGraph(10, 12);
addOrientedEdge(temaTrecuta, 0, 0, 1, 5);
addOrientedEdge(temaTrecuta, 1, 1, 2, 3);
addOrientedEdge(temaTrecuta, 2, 2, 3, 5);
addOrientedEdge(temaTrecuta, 4, 3, 9, 5);
addOrientedEdge(temaTrecuta, 5, 1, 9, 1);
addOrientedEdge(temaTrecuta, 6, 3, 4, 1);
addOrientedEdge(temaTrecuta, 7, 4, 8, 5);
addOrientedEdge(temaTrecuta, 8, 8, 7, 1);
addOrientedEdge(temaTrecuta, 9, 7, 5, 1);
addOrientedEdge(temaTrecuta, 10, 7, 6, 3);
addOrientedEdge(temaTrecuta, 11, 6, 0, 1);

此部分创建图形及其边。createGraph函数将顶点数和边数作为参数。

void addOrientedEdge(Graph* graph, int index, int source, int destination, int cost) {
    graph->edge[index].src = source;
    graph->edge[index].dest = destination;
    graph->edge[index].cost = cost;

    graph->matrix[source][destination] = cost;
}

这是添加新边的函数。

下面是我对Bellman Ford算法的实现。

void bellmanFord(Graph* gr, int src) {
    int* dist = (int*)malloc(sizeof(int) * gr->V);
    int* path = (int*)malloc(sizeof(int) * gr->V);

    if (!path || !dist) {
        printf("Nu am putut aloca.\n");
        exit(1);
    }

    for (int i = 0; i < gr->V; ++i) {
        dist[i] = INT_MAX;
        path[i] = 0;
    }

    path[src] = -1;

    dist[src] = 0;

    for (int i = 1; i <= gr->V - 1; ++i) {
        for (int j = 0; j < gr->E; ++j) {
            int m = gr->edge[j].src;
            int n = gr->edge[j].dest;
            int cost = gr->edge[j].cost;

            if (dist[m] != INT_MAX && dist[m] + cost < dist[n]) {
                dist[n] = dist[m] + cost;
                path[n] = m; 
            }
        }
    }

    for (int i = 0; i < gr->E; ++i) {
        int m = gr->edge[i].src;
        int n = gr->edge[i].dest;
        int cost = gr->edge[i].cost;

        if (dist[m] != INT_MAX && dist[m] + cost < dist[n]) {
            printf("Exista un ciclu negativ.");
            return;
        }
    }

    printBellmanSol(dist, gr->V, path);

    free(dist);
    free(path);
}

共有2个答案

刘兴修
2023-03-14

导致问题的原因是边缘缺失。感谢@user3386109的收看。

邵文乐
2023-03-14

由于没有引用边索引,只要它是唯一的和顺序的,就应该考虑自动递增。除了边缘索引E,还有一个新的边缘容量。这是传递给createGraph的数字,最初设置计数器E=0。您可以使用较少的一个参数编写addorientedge;取下一个边索引。

static void addOrientedEdge(struct Graph* graph, int source, int destination, int cost) {
    const int index = graph->E;
    assert(graph && graph->E < graph->E_capacity);
    graph->edge[index].src = source;
    graph->edge[index].dest = destination;
    graph->edge[index].cost = cost;
    graph->E++;
    graph->matrix[source][destination] = cost;
}

这将使您不必担心边数。

 类似资料:
  • 我知道Bellman-Ford算法最多需要| V |-1次迭代才能找到最短路径,如果图不包含负权重循环。有没有办法修改Bellman-Ford算法,使其在1次迭代中找到最短路径?

  • 我一直试图通过以下资源来理解贝尔曼福特的正确实现:1 如果我们已经知道给定的加权有向图不包含一个圈(因此也没有负圈),是否遵循Bellman-Ford算法的正确实现? 我在上述实现中遇到的第一个问题是,如果图中只有两个节点具有从源节点到目标节点的定向边,那么需要修改for的第一个

  • 我这里有一个更聪明的贝尔曼福特版本: 有人能想到一种图,对于这种图,该算法的时间复杂度下限为(V*E),其中V=#顶点,E=#边 我想看看这个陷阱在哪里。

  • 在具有V节点和E边的有向图中,Bellman-Ford算法将每个顶点(或者更确切地说,每个顶点的边)松弛(V-1)次。这是因为从源到任何其他节点的最短路径最多包含(V-1)条边。在第V次迭代中,如果边可以松弛,则表示存在负循环。 现在,我需要找到被这个负循环“摧毁”的其他节点。也就是说,由于从源到位于负循环中的节点的路径上有一个或多个节点,因此一些不在负循环中的节点现在与源的距离为负无穷远。 实现

  • 经过大量谷歌搜索,我发现大多数消息来源说迪克斯特拉算法比贝尔曼-福特算法“更有效”。但是在什么情况下Bellman-Ford算法比Dijkstra算法更好呢? 我知道“更好”是一个宽泛的说法,所以具体来说,我指的是速度和空间,如果适用的话。当然,在某些情况下,贝尔曼-福特方法比迪克斯特拉方法更好。

  • 我正在努力改进Bellman-Ford算法的性能,我想知道改进是否正确。 我运行松弛部分不是V-1而是V次,并且我得到了一个涉及的布尔变量,如果在外循环的迭代过程中发生任何松弛,则将其设置为。如果在n.迭代中没有发生松弛,其中n 我认为这可能会改善运行时,因为有时我们不必迭代V-1次来找到最短路径,而且我们可以更早地返回,而且它也比用另一块代码检查循环更优雅。