图论·Bellman_ford算法

无负权回路例题
带负权回路例题

Bellman_ford算法

适用条件

  • 单源最短路径
  • 存在负权值边
  • 检测负权回路

核心操作

  • 松弛:对每条边与源点的距离重新计算
cpp 复制代码
if (dist[item.v1] != INT_MAX && dist[item.v1] + item.w < dist[item.v2]) {
			dist[item.v2] = dist[item.v1] + item.w;//dist[item.v1]未更新时应该跳过
}
  • 迭代:可以视为一种逼近 ,利用边的信息一层层迭代,每一层都利用了上一层迭代的结果,所以源点到达各个结点的距离会越来越接近最小值,最终达到终点的距离也会接近最小值(但这好像不是贪心的思想,而只是简单的迭代逼近)

个人代码

cpp 复制代码
using namespace std;
using ll = long long;
int n, m, s, t, v;
struct Edge {
	int v1, v2, w;
};
void solve() {
	cin >> n >> m;
	vector<Edge>edges;
	vector<int>dist(n + 1, INT_MAX); dist[1] = 0;
	while (m--) {
		cin >> s >> t >> v;
		edges.push_back({ s,t,v });
	}
	for (int i = 1; i < n; i++) {
		for (auto item : edges) {
			if (dist[item.v1] != INT_MAX && dist[item.v1] + item.w < dist[item.v2]) {
				dist[item.v2] = dist[item.v1] + item.w;//dist[item.v1]未更新时应该跳过
			}
		}
	}
	if (dist[n] == INT_MAX) {
		cout << "unconnected";
	}
	else {
		cout << dist[n];
	}
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0); std::cout.tie(0);
	solve();
	return 0;
}

判断负权回路

输出结果前多加上一层循环,改掉判断逻辑即可

cpp 复制代码
for (auto item : edges) {
	if (dist[item.v1] != INT_MAX && dist[item.v1] + item.w < dist[item.v2]) {
		cout << "circle";
		return;//return不可以省略
	}
}

注意事项

  • dist[item.v1] != INT_MAX不可以省略
  • vector<Edge>edges;存储方式既不是邻接矩阵也不是邻接表

优化版SPFA

核心操作

  • 队列操作:类似BFS,目的是防止对一个出更新的边进行无意义的操作
  • 存储方式:邻接表

个人代码

cpp 复制代码
using namespace std;
using ll = long long;
int n, m, s, t, v;
struct Edge {
	int vex, weight;
};
void solve() {
	cin >> n >> m;
	vector<int>dist(n + 1, INT_MAX); dist[1] = 0;
	vector<list<Edge>>grid(n + 1, list<Edge>());
	queue<Edge>q;
	while (m--) {
		cin >> s >> t >> v;
		grid[s].push_back({ t,v});
	}
	q.push({ 1,0 });
	while (!q.empty()) {
		Edge cur = q.front();
		q.pop();
		for (auto item : grid[cur.vex]) {
			if (dist[cur.vex] + item.weight < dist[item.vex]) {
				dist[item.vex] = dist[cur.vex] + item.weight;
				q.push(item);
			}
		}
	}
	if (dist[n] == INT_MAX) {
		cout << "unconnected";
	}
	else {
		cout << dist[n];
	}
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0); std::cout.tie(0);
	solve();
	return 0;
}

判断负权回路

只要一个顶点被加入到队列的次数>=n,一定出现了负权回路

  • 定义计数数组
cpp 复制代码
vector<int>count(n + 1, 0);
  • 初始化队列
cpp 复制代码
q.push({ 1,0 }); count[1]++;
  • 队列操作逻辑更新
cpp 复制代码
while (!q.empty()) {
	Edge cur = q.front();
	q.pop();
	if (count[cur.vex] >= n) {//判断加入队列的次数
		cout << "circle";
		return;
	}
	for (auto item : edges[cur.vex]) {
		if (dist[cur.vex] + item.weight < dist[item.vex]) {
			dist[item.vex] = dist[cur.vex] + item.weight;
			q.push(item);
			count[item.vex]++;
		}
	}
}

时间复杂度

  • 朴素版Bellman_ford算法:O(NM),N是顶点数,M是边数
  • SPFA算法:O(KN),N是顶点数,K是个不定值,取决于总共加入多少条边到队列中去
    • 进出队列的时间不计

本文参考于代码随想录

相关推荐
数据大魔方2 分钟前
【期货量化实战】威廉指标(WR)策略:精准捕捉超买超卖信号(Python源码)
开发语言·数据库·python·算法·github·程序员创富
why技术3 分钟前
可怕,看到一个冷血的算法。人心逐利,算法只会更聪明地逐利。
前端·后端·算法
有一个好名字13 分钟前
力扣-最大连续1的个数III
c++·算法·leetcode
橘颂TA19 分钟前
【剑斩OFFER】算法的暴力美学——力扣 43 题:字符串相乘
数据结构·算法·leetcode·职场和发展·哈希算法·结构与算法
海边的Kurisu20 分钟前
代码随想录算法第六十四天| To Be Continued
算法
less is more_093021 分钟前
文献学习——极端高温灾害下电缆型配电网韧性提升策略研究
笔记·学习·算法
小芒果_0122 分钟前
P8662 [蓝桥杯 2018 省 AB] 全球变暖
c++·算法·蓝桥杯·信息学奥赛
漫随流水26 分钟前
leetcode算法(199.二叉树的右视图)
数据结构·算法·leetcode·二叉树
jghhh0128 分钟前
自适应信号时频处理方法MATLAB实现(适用于非线性非平稳信号)
开发语言·算法·matlab
信奥卷王29 分钟前
2025年12月GESPC++一级真题解析(含视频)
算法