最短路之Bellman-ford 算法

Bellman-ford 算法

算法摘要

作用:单源有向图上求最短路
特点:能适应负权边的情况
思想:动态规划
时间复杂度: O(点数×变数)
原理:对所有的边进行n-1轮松弛操作,(n个顶点的图中,任意两点之间的路径最多包含n-1边)
注意事项:需要判断是否产生负权回路 (再对边进行一次内部循环,如果还有可以松弛的点,说明有负权回路)

c++代码

#include<iostream>
#include<vector>
#define ARRAY vector<int> //下标从0开始有效
#define INF	99999999
using namespace std;

struct Edge {
	int from;
	int to;
	int val;
};

vector<Edge> edges;
int nodesNum, edgeNum, startPoint;

int main(){
	//获取输入输入
	scanf("%d %d %d", &nodesNum, &edgeNum, &startPoint);
	for (int i = 0; i < edgeNum; i++) {
		int from, to, val;
		scanf("%d %d %d", &from, &to, &val);
		edges.push_back({ from, to, val });
	}

	//计算最短路
	ARRAY distance(nodesNum+1, INF);	//从startPoint到各点的最短距离,下标从1开始有效
	distance[startPoint] = 0;
	for (int i = 0; i < nodesNum; i++) {
		bool change = false;	//标记是否发生松弛
		for (int j = 0; j < edges.size(); j++){
			Edge tmp = edges[j];
			if (distance[tmp.to] > distance[tmp.from] + tmp.val){
				distance[tmp.to] = distance[tmp.from] + tmp.val;
				change = true;
			}
		}
		if (!change) {	//若没有松弛则结束算法
			break;
		}
	}
	//判断是否有负权回路
	bool vaild = true;
	for (int i = 0; i < edges.size() && vaild; i++){
		Edge tmp = edges[i];
		if (distance[tmp.to] > distance[tmp.from] + tmp.val){
			vaild = false;
		}
	}
	//输出结果
	if (!vaild){
		cout << "Fail\n";
		return 0;
	}
	cout << "Success\n";
	for (int i = 1; i <= nodesNum; i++){
		printf("nodes: %d    distance: %d \n", i, distance[i]);
	}
	cout << endl;
	return 0;
}

后记

  1. 注意事项:注意图的类型,是有向还是无向图。说是无向图,则edges数组实际的长度是nodeNum的两倍,循环时不能用nodeNum.
  2. 易错点:注意数组下标关系,第一个节点在下标0还是下标
  3. 发现:无向图出现负权边则意味则产生负权回路,这时不能求最短路。所以负权边的情况只出现在单向图中。
发布了90 篇原创文章 · 获赞 31 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/BlackCarDriver/article/details/104691979
今日推荐