(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