最近在研究AGV系统的调度算法,为了实现多AGV小车的运行,给每一个AGV小车规划一条最优路径,对比了Bellman-Ford算法、SPFA算法、Dijkstra算法、Floyd算法和A*算法的优缺点,最终确定了使用A*算法作为路径规划算法。
下面总结下几种算法:
1、Bellman-Ford算法
(1)贝尔曼-福特算法是计算从源点到任意一点的最短路径的长度,初始化数组dist[0]为0,dist[i]为无穷大。
(2)以下操作循环执行至多n-1次,n为顶点数:
对于每一条边 edge(Start,End),如果dist[Start] +Weight(Start, End)
为了检测图中是否存在负环路,即权值之和小于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节点的距离;
Bellman-Ford算法可以大致分为三个部分
第一,初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。
第二,进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。
第三,遍历途中所有的边(edge(u,v)),判断是否存在这样情况:d(v)> 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
#include
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
贝尔曼算法的时间复杂度是O(V*E),是非常大的,所以它的效率非常低。