《算法导论》第24章-单源最短路径 引入&& 24.1 Bellman-Ford算法

一、引入(略微了解一下是啥)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KeepCoding♪Toby♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值