洛谷---P5960---差分约束算法(模板)

洛谷---P5960---差分约束算法(模板)_第1张图片
洛谷---P5960---差分约束算法(模板)_第2张图片

输入样例

3 3
1 2 3
2 3 -2
1 3 1

实现思路

这题用到了一种名为差分约束系统的思想,将差分约束转化为图论问题。我个人理解为求交集,即求上界时为求所有上界集合的最小值(即最短路径),求下界时为求下界集合的最大值(即最长路径, 可以用SPFA改 松弛方向来实现)。

差分约束的思想可以参考这篇博客:差分约束入门

实现代码

#include
#include
#include
#include
using namespace std;

const int maxn = 5e3 + 5;
const int Inf = 0x3f3f3f3f;

typedef pair<int, int> Edge;
vector<Edge> edge[maxn];
int n, m;
int dis[maxn], inq[maxn], clc[maxn];

bool spfa(int u) {
	memset(dis, Inf, sizeof(dis));
	memset(inq, 0, sizeof(inq));
	memset(clc, 0, sizeof(clc)); // 用来判断是否存在负环,遍历点达到n时即存在环
	dis[u] = 0, inq[u] = 1;
	queue<int> q;
	q.push(u);
	while (q.size()) {
		u = q.front(); q.pop(); inq[u] = 0;
		for (int i = 0; i < edge[u].size(); i++) {
			int v = edge[u][i].first, d = edge[u][i].second;
			if (dis[v] > dis[u] + d) {
				dis[v] = dis[u] + d;
				if (!inq[v]) {
					q.push(v);
					inq[v] = 1;
					if (++clc[v] == n) return false; // 存在负环,返回
				}
			}
		}
	}
	return true;
}

int main() { 
	int u, v, y;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) edge[0].push_back(Edge(i, 0)); // 这里约束到一个超级原点来使得各个dis同时符合约束条件
	for (int i = 1; i <= m; i++) {
		cin >> v >> u >> y;
		edge[u].push_back(Edge(v, y));
	}

	if (!spfa(0)) cout << "NO" << endl;
	else for (int i = 1; i <= n; i++) cout << dis[i] << " ";
	return 0;
}

你可能感兴趣的:(C++,差分约束,洛谷,差分约束,SPFA,C++,洛谷,P5960)