一、引入(略微了解一下是啥)
1、关于负权重的边
直接截图,书上说得很清晰。
2、最短路径树的相关特点
3、松弛操作
我们对每一个结点维持一个属性v.d,用来记录从源节点s到结点v的最短路径权重的上限。我们称v.d为s到v的最短路径的估计。
初始化
INITIALIZE-SINGLE-SOURCE(G,s)
for each vertex v ∈ G.V
v.d = ∞
v.π = NIL
s.d = 0
RELAX(u,v,w)
//在松弛操作中,如果一个点v的最短路径值大于u.d加上(u,v)的权重
if v.d > u.d + w(u,v)
v.d = u.d + w(u,v)//更新v.d
v.π = u //让u直接成为v的前驱结点,因为u之前不是后者的前驱
举个例子:
4、最短路径和松弛操作的性质
二、Bellman-Ford算法
Bellman-Ford算法通过对边进行松弛操作来降低从源结点s到每个结点v的最短路径的v.d,直到估计值和实际的最短路径权重δ(s,v)相同时为止。
BELLMAN-FORD(G,w,s)
INITIALIZE-SINGLE-SOURCE(G,s)
for i = 1 to |G.V-1|
for each edge(u,v)∈G.E
RELAX(u,v,w)
for each edge(u,v)∈G.E
if v.d > u.d + w(u,v)
return FALSE
return TRUE
注意图里备注的次序,这个很重要!
三、一些引理
#include <iostream>
using namespace std;
//表示一条边
struct Edge
{
//首尾顶点
int pre;
int next;
int weight;//权重
};
//带权值的有向图
struct Graph {
//顶点数和边数
int V;
int E;
Edge* edge;//指针
};
//创建图
Graph* CreateGraph(int v, int e)
{
Graph* graph = new Graph();
graph->E = e;
graph->V = v;
graph->edge = new Edge();
return graph;
}
//打印结果
void show(int dist[],int n)
{
cout << "单源最短路径" << endl;
for (int i = 0; i < n; i++) {
if (dist[i] == INT_MAX) {
cout << "与节点" << i << "距离->无穷大" << endl;
}//if
else {
cout << "与节点" << i << "距离->" << dist[i] << endl;
}
}
}
//单源最短路径
bool BellmanFord(Graph* graph, int pre)
{
int v = graph->V;
int e = graph->E;
//存储距离的数组
int dist[100];
//初始化
for (int i = 0; i < v; i++) {
dist[i] = INT_MAX;
}
dist[pre] = 0;
Edge edge;
int a, b, weight;
for (int i = 1; i < v; i++) {
for (int j = 0; j < e; j++) {
edge = graph->edge[j];
a = edge.pre;
b = edge.next;
weight = edge.weight;
if (dist[a] != INT_MAX && dist[a] + weight < dist[b]) {
dist[b] = dist[a] + weight;
}
}
}
//检测负权回路
bool isBack = false;
for (int i = 0; i < e; i++) {
edge = graph->edge[i];
a = edge.pre;
b = edge.next;
weight = edge.weight;
if (dist[a] != INT_MAX && dist[a] + weight < dist[b]) {
isBack = true;
break;
}
}
show(dist, v);
return isBack;
}
//单源最短路径
int main() {
int v = 7;
int e = 9;
Graph* graph = CreateGraph(v, e);
graph->edge[0].pre = 0;
graph->edge[0].next = 1;
graph->edge[0].weight = -1;
graph->edge[1].pre = 0;
graph->edge[1].next = 2;
graph->edge[1].weight = 4;
graph->edge[2].pre = 1;
graph->edge[2].next = 2;
graph->edge[2].weight = 3;
graph->edge[3].pre = 1;
graph->edge[3].next = 3;
graph->edge[3].weight = 2;
graph->edge[4].pre = 1;
graph->edge[4].next = 4;
graph->edge[4].weight = 2;
graph->edge[5].pre = 3;
graph->edge[5].next = 2;
graph->edge[5].weight = 5;
graph->edge[6].pre = 3;
graph->edge[6].next = 1;
graph->edge[6].weight = 1;
graph->edge[7].pre = 4;
graph->edge[7].next = 3;
graph->edge[7].weight = -3;
graph->edge[8].pre = 5;
graph->edge[8].next = 6;
graph->edge[8].weight = 2;
bool result = BellmanFord(graph, 0);
if (result) {
cout << "图中存在回路" << endl;
}//if
else {
cout << "图中不存在回路" << endl;
}//else
return 0;
}