Bellman-Ford算法用于求单源最短路包含负权边的问题,还可以检测图中是否有负环

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define IOS ios::sync_with_stdio(false)
#define endl '\n'

using namespace std;
typedef long long ll;
typedef pair<int, int>p;

const int maxn = 205;
int n, m;
int d[maxn], pre[maxn];
struct E {
   
	int u, v, w;
}edge[maxn * maxn];

void init() {
   
	for (int i = 0;i <= n;++i)d[i] = INF;
}
int main() {
   
	while (~scanf("%d%d", &n, &m)) {
   
		init();
		for (int i = 1;i <= m;++i) {
   
			//无向图
			int x, y, z;cin >> x >> y >> z;
			edge[i].u = x;
			edge[i].v = y;
			edge[i].w = z;
			edge[i + m].u = y;
			edge[i + m].v = x;
			edge[i + m].w = z;
		}
		int s, t;
		scanf("%d%d", &s, &t);//起点和终点
		d[s] = 0;
		//Bellman-Ford核心代码
		for (int i = 0;i < n - 1;++i) {
   
			for (int i = 0;i < n;++i)pre[i] = d[i];
			for (int j = 1;j <= 2*m;++j) {
   
				if (d[edge[j].u] > d[edge[j].v] + edge[j].w)
					d[edge[j].u] = d[edge[j].v] + edge[j].w;
			}
			//小优化/
			int check = 0;
			for (int i = 0;i < n;++i)
				if (pre[i] != d[i]) {
   
					check = 1;
			}
			if (!check)break;
			//如果d数组和pre数组完全一样 说明不需要继续松弛 提前退出循环
		}
		//
		//若经过n-1轮松弛后最短路径仍然会变化 说明存在负环
		int flag = 0;
		for (int i = 1;i <= 2 * m;++i)
			if (d[edge[i].u] > d[edge[i].v] + edge[i].w)
				flag = 1;
		//
		if (flag)printf("此图存在负环");
		if (d[t] != INF)printf("%d\n", d[t]);
		else printf("-1\n");
	}
}