中级篇——Bellmen算法求最短路径

本文介绍Bellmen算法,一种适用于有向图中寻找最短路径的算法,尤其在边权重允许为负的情况下表现突出。文章提供了核心代码及示例,演示了如何通过n-1轮松弛迭代来确定两点间最短路径。

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

        Bellmen算法是求最短路径的最方便的算法之一,SPFA算法更方便,是Bellmen算法的队列实现但队列不会,掌握Bellmen算法即可解决大部分最短路径的问题。Bellmen算法的最大优势就在于可以解决边权值为负的情况。(限于有向图)

        另外,Bellmen算法的运算时间为O(nm)适合n^2>m的稀疏图!!!当遇到n^2<m的稠密图时最好用Dijkstra算法,其运算时间为O(n^2)。

典例:给n个点,m条路径,求A点到B点的最短路径。

需要开设dis[]记录,dis[i]即到达i点的最短距离,输出时输出dis[i]即可。

*核心代码:

for(int i=1;i<=n-1;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
                    dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
            }
        }

理论上一共要进行n-1轮松弛,但有可能最后几轮的松弛将不再改变dis[]中的值,故可以提前结束循环节省运算时间。需要一个与dis[]一样大的数组dis1[]备份dis[]的值,另外还引进一个flag变量初始化为0。每次松弛过后将dis[]与dis1[]中的值一一比对,若相同则flag=1;判断if(flag==1)则结束循环无需再松弛。

#include <iostream>
#include<stdio.h>
#define max 99999999
using namespace std;
int dis[200],dis1[200],n,m,a,b;
struct node
{
    int u,v,w;       //起点。重点,权值
}edge[100];
void init()          //初始化
{
    for(int i=1;i<=n;i++)
        dis[i]=max;  //初始化将到达每个点的距离设为无穷
    dis[a]=0;      //起点开始故距离为0
}
int main()
{
    while(cin>>n>>m>>a>>b)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            cin>>edge[i].u>>edge[i].v>>edge[i].w;
        }
        //bellmen核心语句!!!
        int flag;
        for(int i=1;i<=n-1;i++)
        {
            flag=0;  
            for(int j=1;j<=m;j++)
            {
                if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
                    dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
            }
	    for(int j=1;j<=n;j++)
            	if(dis[j]!=dis1[j])
                { 	      	     
                     flag=1;dis1[j]=dis[j];
                } 
            if(flag==0) break;   //若值均未变则跳出循环
        }
        //输出结果
        cout<<dis[b]<<endl;
    }
    return 0;
}


数据:

Input:5   5   1   5

             2   3   2

             1   2   -3

             1   5   5

             4   5   2

             3   4   3

Output:4

运算过程(理解运算原理)

初始化:dis     1           2            3          4          5

                           0       max       max     max     max

第一轮:先处理第一条边,2——>3距离为2,此时dis[2]和dis[3]均为max,无法比较,松弛失败。第二条边1——>2距离为-3,此时dis[1]=0,dis[2]=max,dis[2]>dis[1]+(-3),故dis[2]值变为-3。第三条边1——>5距离为5,dis[5]>dis[1]+5,故dis[5]=5。以此方法,第三四条边无法松弛,故第一轮松弛结束。

                dis     1           2            3          4          5

                           0         -3         max      max       5

第二轮:处理刚才未松弛成功的第一条边2——>3,dis[3]>dis[2]+(-3),dis[3]=-1。之后3——>4,dis[4]>dis[3]+3,dis[4]=2。发现了从4——5距离会比1——>5短,但松弛3——>4时已经过了4——>5的边,只能再进行一轮松弛。

                dis     1           2            3          4          5

                           0         -3            -1         2          5

第三轮:处理4——>5,dis[5]>dis[4]+2,dis[5]=4。

                dis     1           2            3          4          5

                           0         -3            -1         2          4

第四轮:无变化的值,flag=0,跳出循环。

                dis     1           2            3          4          5

                           0         -3            -1         2          4





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值