浅谈路径规划算法之Bellman-Ford算法

来源:互联网 发布:袅袅虚拟歌手 mac 编辑:程序博客网 时间:2024/05/29 15:43

  最近在研究AGV系统的调度算法,为了实现多AGV小车的运行,给每一个AGV小车规划一条最优路径,对比了Bellman-Ford算法、SPFA算法、Dijkstra算法、Floyd算法和A*算法的优缺点,最终确定了使用A*算法作为路径规划算法。

 

下面总结下几种算法:

1Bellman-Ford算法 

1)贝尔曼-福特算法是计算从源点到任意一点的最短路径的长度,初始化数组dist[0]0dist[i]为无穷大。

2)以下操作循环执行至多n-1次,n为顶点数:

   对于每一条边 edge(Start,End),如果dist[Start] +Weight(Start, End)<dist[End],则令dist[End] =dist[Start]+Weight(Start, End)。若上述操作没有对dist进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;

为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边dge(Start,End),如果存在dist[Start] + Weight(Start, End) < dist[End]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组dist[n]中记录的就是源点s到各顶点的最短路径长度。

       注释:Start是一条有向边的起点,End是一条有向边的终点;edge(Start,End)为节点Start和节点End之间边;Weight(Start, End)为节点Start和节点End之间的边的权值;dist[i]是指源节点到i节点的距离;

BellmanFord算法可以大致分为三个部分
第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
第二,进行循环,循环下标为从1n1n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
第三,遍历途中所有的边(edgeuv)),判断是否存在这样情况:dv> d (u) + w(u,v)则返回false,表示途中存在从源点可达的权为负的回路。

 !!!之所以需要第三部分的原因,是因为,如果存在从源点可达的权为负的回路。则 应为无法收敛而导致不能求出最短路径。

                             

经过第一次遍历后,点B的值变为5,点C的值变为8,这时,注意权重为-10的边,这条边的存在,导致点A的值变为-2。(8+ -10=-2

                               

第二次遍历后,点B的值变为3,点C变为6,点A变为-4。正是因为有一条负边在回路中,导致每次遍历后,各个点的值不断变小。所以这是无限循环的。

下面是Bellman-Ford算法的实现代码:


#include <iostream>#include <stdio.h>using namespace std;const int maxnum=100;   //最大边数const int maxint=9999;  //源点和某点不可达时的距离//有向边的结构体typedef struct Edge{    int Start; //有向边边的起始点    int End;   //有向边的终点    int Weight;//边的权重}Edge;Edge edge[maxnum];//有向边的数组int dist[maxnum]; //距离数组//节点的数目、边的数目、源节点的下标int nodenum,edgenum,source;//初始化函数void Init(){    cin>>nodenum>>edgenum>>source;    for(int i=1;i<=nodenum;i++)        dist[i]=maxint;    dist[source]=0;    for(int i=1;i<=edgenum;i++)    {        cin >> edge[i].Start >> edge[i].End >> edge[i].Weight;        if(source==edge[i].Start)        {            dist[edge[i].End]=edge[i].Weight;        }    }}//松弛函数void Relax(int Start,int End,int Weight){    if(dist[End]>dist[Start]+Weight)        dist[End]=dist[Start]+Weight;}//贝尔曼福特函数bool Bellman_Ford(){    for(int i=1;i<=nodenum-1;i++)    {        for(int j=1;j<=edgenum;j++)        {            Relax(edge[j].Start,edge[j].End,edge[j].Weight);        }    }    bool flag=1;    for(int i=1;i<=edgenum;i++)    {        //判断是否存在负回路        if(dist[edge[i].End]>dist[edge[i].Start]+edge[i].Weight)        {            flag=0;            break;        }    }    return flag;}int main(){    freopen("out.txt","r",stdin);//打开txt    Init();    if(Bellman_Ford())    {        for(int i=1;i<nodenum;i++)            cout<<dist[i]<<endl;//打印源节点到每个节点的距离    }    return 0;}

   贝尔曼算法的时间复杂度是O(V*E),是非常大的,所以它的效率非常低。


2 0
原创粉丝点击