Bellman—Ford算法实现(解决存在负边情况下单源最短路径问题)

(1)BellmanFord算法能够在存在负边权值的情况下,解决单源最短路径问题,其时间复杂度为O(VE)。

          算法实验思想以及算法正确性分析主要参考《算法导论》中单源最短路径一章。

         

(2)代码中图的实现采用邻接表,图的节点编号从0开始计数。算法输入图的结构,输出从源点到各个节点的最短距离

#include <iostream>  
#include <string.h>  

using namespace std;  

#define MAX_NODE 1000  
#define INFINITY   9999999
#define NIL   -1

typedef struct ArcNode  
{  
	int adjvex;//弧指向的节点的值(点的标号)  
	int distance;//两点之间的距离
	int weight; //边的权重
	ArcNode* next;//指向下一条弧  
	ArcNode(int value)  
	{  
		adjvex = value;  
		next = NULL;  
	}  
};//邻接表节点  

typedef struct  
{  
	int vexdata; //头节点的标号  
	struct ArcNode* firstarc;//第一个邻接表节点的地址  
}VexNode, AdjList[MAX_NODE];//头结点  

typedef struct  
{  
	AdjList vexNodes;  
	int vexNum;  
	int arcNum;//当前节点数目和弧数  
}GraphWithAL;//邻接表表示的图  

//检测要输入的边是否已经存在,针对无向图  
bool CheckArcIsExist(GraphWithAL* G, int v1, int v2)  
{  
	ArcNode* temp = G->vexNodes[v1].firstarc;  
	while(temp!=NULL)  
	{  
		if(temp->adjvex == v2)  
			return true;  
		temp = temp->next;  
	}  
	return false;  
}  

//创建图,vexNum代表顶点的个数,arcNum代表边的个数,isUnDirected代表的是 是否是无向图  
void CreateGraph(GraphWithAL* G, int vexNum, int arcNum)  
{  
	memset(G, 0 ,sizeof(GraphWithAL));  
	//初始化头结点  
	int i = 0;  
	for(i=0; i<vexNum; ++i)  
	{  
		G->vexNum = vexNum;  
		G->vexNodes[i].firstarc = NULL;  
		G->vexNodes[i].vexdata = i;//从0开始计算顶点  
	}  
	//初始化边  
	for(i=0; i<arcNum; ++i)  
	{  
		//输入边的顶点和尾点  
		int v1, v2, weight;  
		cin>>v1>>v2>>weight;  
		if(CheckArcIsExist(G, v1, v2))  
			continue;  
		ArcNode* arcNode = new ArcNode(v2);  
		//还需要检验边是否已经存在,这里没有检验  
		arcNode->next = G->vexNodes[v1].firstarc; 
		arcNode->weight= weight;
		G->vexNodes[v1].firstarc = arcNode;  
		G->arcNum++;   
	}  
}  
void printResult(int d[], int pi[], int n)
{
	int i=0;
	for(; i<n; ++i)
		cout<<d[i]<<" ";
	cout<<endl;
}
void InitialSingleSource(int s, int d[], int pi[], int num)
{
	int i=0;
	for(; i<num; ++i)
	{
		d[i] = INFINITY;
		pi[i] = NIL;
	}
	d[s] = 0;
}
//松弛操作
void Relax(int u, int v, int weight, int d[], int pi[])
{
	if(d[v] > d[u]+weight)
	{
		d[v] = d[u] +weight;
		pi[v] = u;
	}
}

bool BellmanFord(GraphWithAL* G, int s, int d[], int pi[])
{
	InitialSingleSource(s, d, pi, G->vexNum);
	//printResult(d, pi, 5);
	int i = 0;
	ArcNode* temp = NULL;
	for(int j=0; j<G->vexNum-1; ++j)
	{
		for(i = 0; i<G->vexNum; ++i)
		{

			temp = G->vexNodes[i].firstarc;
			while(temp != NULL)
			{
	
				Relax(i, temp->adjvex, temp->weight, d, pi);
				temp = temp->next;
				printResult(d, pi, G->vexNum);
			}
		}
	}
	return true;
}


int main()  
{  
	GraphWithAL G;  
	int n, m;  
	while(cin>>n>>m)  
	{  
		if(n==0)  
			break;
		CreateGraph(&G, n, m);  
		int d[5];
		int pi[5];
		BellmanFord(&G, 1, d, pi);
		printResult(d, pi, G.vexNum);
	}
	return 0;  
}  

实验数据:


5 10 //图中总共有5个节点,10条边

//下面为10条边的具体信息:  源点   目标节点  权值

0 1 6

0 3 7

1 3 8

1 2 5

1 4 -4

2 1 -2

3 2 -3

3 4 9

4 2 7

4 0 2




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值