差分约束学习笔记

对于多个形如 x - y <= a 的不等式
我们将其变形 变成 x <= y + a
如果由 y 到 x 建一条边权为 a 的边然后跑最短路
那么 dis[x] <= dis[y] + a 恒成立 得到一组通解
若图中出现了负环 说明无最短路 进而说明无解
并且为了维护图的连通性 可以加一个超级原点 对所有的点连一条边权为 0 的边 然后作为起点跑最短路

当然可以用spfa 这里另外介绍一种基于spfa的bellman-ford算法
首先对于spfa判负环 在不考虑重边的情况下 我们判的是松弛次数 如果松弛次数 >= n 即为有负环
而bellman-ford的算法的原理是 n次对所有点进行松弛操作 若最后一次还有点可以被松弛 就证明有负环存在
code:

bool bellman_ford(int s) {
	memset(dis, 0x3f, sizeof dis );
	dis[s] = 0;
	bool flag;
	for (int i = 1; i <= n; ++i) {
		flag = 0;
		for (int j = 1; j <= n; ++j) {
			for (int k = head[j]; k; k = nxt[k]) {
				int y = to[k];
				if (dis[y] > dis[j] + len[k]) {
					dis[y] = dis[j] + len[k];
					flag = 1;
				}
			}
		}
		if (flag == 0) break;
	}
	return flag;
}

当然 这种做法会出现一些小小的问题
因为我们钦定 dis[s] = 0 并且由 s 向每个点都建了一条边权为 0 的边
那么实际上对于每个点 i 都有 dis[i] <= dis[s] + 0 即 dis[i] <= 0
这时我们求出来的所有值都是 <= 0 的
但是很多时候我们要求的是要让所有值 >= 0
这里有两种解决办法:

  • 求出最小的那个负值 然后全体减掉这个负值
  • 把 x - y <= a 变形为 y >= a + x 然后跑最长路 这样对于每个点都有 dis[i] >= dis[s] + 0 即 dis[i] >= 0

至于具体用哪种 就见仁见智了

例题:P1260 工程规划

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 0721;
int head[N], nxt[N], to[N], len[N], cnt;
int dis[N], vis[N];
bool exist[N];
int n, m;

inline void cmb(int x, int y, int z) {
	to[++cnt] = y;
	len[cnt] = z;
	nxt[cnt] = head[x];
	head[x] = cnt;
}

bool bellman_ford(int s) {
	memset(dis, 0x3f, sizeof dis );
	dis[s] = 0;
	bool flag;
	for (int i = 1; i <= n; ++i) {
		flag = 0;
		for (int j = 1; j <= n; ++j) {
			for (int k = head[j]; k; k = nxt[k]) {
				int y = to[k];
				if (dis[y] > dis[j] + len[k]) {
					dis[y] = dis[j] + len[k];
					flag = 1;
				}
			}
		}
		if (flag == 0) break;
	}
	return flag;
}


int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; ++i) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		cmb(y, x, z);
	}
	for (int i = 1; i <= n; ++i) cmb(0, i, 0);
	
	if (bellman_ford(0))
		printf("NO SOLUTION");
	else {
		int minn = 0x7fffffff;
		for (int i = 1; i <= n; ++i) minn = min(minn, dis[i]);
		for (int i = 1; i <= n; ++i) printf("%d\n",dis[i] - minn);
	}
	
	return 0;
}
posted @ 2023-05-30 20:31  Steven24  阅读(14)  评论(0编辑  收藏  举报