Algorithm 最短路径算法ford

本文深入探讨了Ford算法在求解带负权边的图中的最短路径问题,详细解释了为何需要进行n-1次迭代来确保正确性,并通过示例代码展示了如何实现该算法及如何检测负权环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看了看最短路径的ford算法,刚看时并没有看懂,我一直想不明白的是在迭代的过程中,每一次都要把每条边,进行松弛(就是判断dist[i]与dist[v]+w[v][i]的情况),我开始的认为是只需要一次的迭代就可以解决的,为什么需要n-1次呢,而且有那么一句话是这样说的,第一次迭代是把将与V0有连接的第一层得到最小值,第二次是将距离V0两条边的点求出来。。。其实在
  1. if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  
  2.             {  
  3.                 dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;  
  4.                 pre[edge[j].v] = edge[j].u;  
  5.             }
  6. 的过程中我想的一次就能解决的情况是比较特殊的,因为你不知道这边出来的顺序是怎么样的,但是第一次的迭代肯定能将与V0有一条距离的边得到我们想要的最小值,这样第二次就能保证与V0有两条边距离的点求出,并且保证是最小值。
  7. 而且ford算法也是有优点在的,他较之前的Djikstra算法有两个好处,一是它可以考虑进去权值为负数的,二,它还可以判断给我们的图中是否存在负环路的能力。

下面贴上该过程的全代码

<span style="font-size:18px;">    #include  
    #include  
    using namespace std;  
      
    #define MAX 0x3f3f3f3f  
    #define N 1010  
    int nodenum, edgenum, original; //点,边,起点  
    typedef struct Edge //边  
    {  
        int u, v;  
        int cost;  
    }Edge;  
    Edge edge[N];  
    int dis[N], pre[N];  
    bool Bellman_Ford()  
    {  
        for(int i = 1; i <= nodenum; ++i) //初始化  
            dis[i] = (i == original ? 0 : MAX);  
        for(int i = 1; i <= nodenum - 1; ++i)  
            for(int j = 1; j <= edgenum; ++j)  
                if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  
                {  
                    dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;  
                    pre[edge[j].v] = edge[j].u;  
                }  
                bool flag = 1; //判断是否含有负权回路  
                for(int i = 1; i <= edgenum; ++i)  
                    if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)  
                    {  
                        flag = 0;  
                        break;  
                    }  
                    return flag;  
    }  
      
    void print_path(int root) //打印最短路的路径(反向)  
    {  
        while(root != pre[root]) //前驱  
        {  
            printf("%d-->", root);  
            root = pre[root];  
        }  
        if(root == pre[root])  
            printf("%d\n", root);  
    }  
      
    int main()  
    {  
        scanf("%d%d%d", &nodenum, &edgenum, &original);  
        pre[original] = original;  
        for(int i = 1; i <= edgenum; ++i)  
        {  
            scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);  
        }  
        if(Bellman_Ford())  
            for(int i = 1; i <= nodenum; ++i) //每个点最短路  
            {  
                printf("%d\n", dis[i]);  
                printf("Path:");  
                print_path(i);  
            }  
        else  
            printf("have negative circle\n");  
        return 0;  
    }
</span>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值