Bellman-Ford贝尔曼福特算法实现

作为一种单源最短路径算法,Bellman-Ford对于有向图和无向图都能适用,它还有一个Dijkstra算法无法具备的特点,那就是对含负权图的最短路径搜索。

每i轮对边的遍历之后,只要不存在负权回路,Bellman-Ford算法都可以保证获得距离源点i条边的点的最短路径。因为最短路径的最大长度不会超过n条边,n为节点的数目。所以n次遍历后所有的节点必定都能找到最短路径。如果n次后还可以继续松弛,则表明该图存在负权回路,可以对代码稍作修改来计算负权环的大小,此处不再做说明。

Bellman-Ford算法的流程如下:
给定图G(V, E)(其中VE分别为图G的顶点集与边集),源点s数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n], Distant[s]0

以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;

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

可知,Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E).

/*
*贝尔曼福特算法-解决单元最短路径问题
*对于带负权的情况同样适用
*通过松弛操作来进行长度缩短
*/

#include<iostream>
using namespace std;

#define IniDis   88888888     //初始各个点到起始点的距离

struct Edge             //边的结构体,包括起始点和目的点以及边的权值
{
	int from;
	int to;
	int cost;
};
int *Distance = NULL;  //各个点到起始点的距离
int *pre = NULL;  //定义某个路径上某个点的前一个点的编号

//主题算法函数,参数为边信息,边数目,点数目,起始点
int Bellman_ford(Edge *edgeInfo, int nEdgeNum,int nNodeNum, int startPoint)
{
	
	Distance = (int *) malloc(2*nNodeNum*sizeof(int));
	pre = (int*)malloc(2*nNodeNum*sizeof(int));
	if (Distance == NULL || pre == NULL)
	{
		return -1;
	}
	//初始化所有节点到初始节点的距离
	memset(Distance, IniDis, 2*nNodeNum*sizeof(int));
	Distance[startPoint] = 0;

	for (int i = 1; i< nNodeNum+1; i++)
	{
		for (int j = 0; j < nEdgeNum; j++)
		{
			if (Distance[edgeInfo[j].from] + edgeInfo[j].cost < Distance[edgeInfo[j].to])   //新路径比老路径更短
			{
				Distance[edgeInfo[j].to] = Distance[edgeInfo[j].from] + edgeInfo[j].cost; //松弛操作
				pre[edgeInfo[j].to] = edgeInfo[j].from;  //更新来源点

			}
		}
	}

	for (int k =1; k< nNodeNum+1; k++)
	{
		if (Distance[edgeInfo[k].from] + edgeInfo[k].cost < Distance[edgeInfo[k].to])
		{
			return -2;  //代表有负权回路
		}
	}
	return 0;

}

//打印源点到各个点的信息
void PrintRoad(int nNodeNum)
{
	for (int i = 1; i< nNodeNum+1; i++)
	{
		cout<<"源点距离点"<<i<<"的路径长度为:"<<Distance[i]<<endl;

	}
}

int main()
{
	int nodenum,edgenum,startpoint;
	int flag = 0;
	Edge *pEdgeInfo = NULL; //存储边信息的指针数组
	cout<<"输入图的节点数目,边数目和起始点编号"<<endl;
	cin>>nodenum>>edgenum>>startpoint;

	pEdgeInfo = (Edge *)malloc(edgenum*sizeof(Edge));
	if (pEdgeInfo == NULL)
	{
		cout<<"分配失败,退出"<<endl;
		return -1;
	}
	
	//为各条边添加初始信息
	for (int i = 0; i< edgenum; i++)
	{
		cin>>pEdgeInfo[i].from >>pEdgeInfo[i].to >>pEdgeInfo[i].cost;
	}
	flag = Bellman_ford(pEdgeInfo, edgenum,nodenum, startpoint);
	if (flag == -1)
	{
		cout<<"初始化失败"<<endl;
	}
	else if (flag == -2)
	{
		cout<<"路径有负权回路"<<endl;
	}
	else
	{
		PrintRoad(nodenum);
	}
	free(pEdgeInfo);
	free(Distance);
	free(pre);
	system("pause");
	return 0;

}

测试数据:

4 6 1
1 2 20
1 3 5
4 1 -200
2 4 4
4 2 4
3 4 2

和:

4 6 1
1 2 2
1 3 5
4 1 10
2 4 4
4 2 4
3 4 2

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/firechungelaile/article/details/22798623
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞