图论·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是个不定值,取决于总共加入多少条边到队列中去
    • 进出队列的时间不计

本文参考于代码随想录

相关推荐
Swift社区22 分钟前
LeetCode 394. 字符串解码(Decode String)
算法·leetcode·职场和发展
tt5555555555551 小时前
LeetCode进阶算法题解详解
算法·leetcode·职场和发展
让我们一起加油好吗1 小时前
【基础算法】DFS中的剪枝与优化
算法·深度优先·剪枝
Q741_1472 小时前
C++ 模拟题 力扣495. 提莫攻击 题解 每日一题
c++·算法·leetcode·模拟
Felven2 小时前
A. Be Positive
算法
小O的算法实验室2 小时前
2026年COR SCI2区,自适应K-means和强化学习RL算法+有效疫苗分配问题,深度解析+性能实测,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
青岛少儿编程-王老师3 小时前
CCF编程能力等级认证GESP—C++7级—20250927
数据结构·c++·算法
夏鹏今天学习了吗3 小时前
【LeetCode热题100(39/100)】对称二叉树
算法·leetcode·职场和发展
天选之女wow4 小时前
【代码随想录算法训练营——Day34】动态规划——416.分割等和子集
算法·leetcode·动态规划
Boop_wu5 小时前
[数据结构] 哈希表
算法·哈希算法·散列表