【差分约束】POJ_1201 Intervals

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SSL_hzb/article/details/88872940

题意

给出 n n 个形如 a   b   c “a\ b\ c” 的式子,表示在 a a b b 之间至少有 c c 个不同的数。求出满足这 n n 个条件的序列的最小长度。

思路

d [ i ] d[i] 0 i 0\sim i 的数字中有多少个在序列里,由题意得 d b d a 1 c d_b-d_{a-1}\geq c

我们可以发现,这个式子很像最短路中的松弛操作 d v > = d u + w ( u , v ) d_v>=d_u+w(u,v) 。那么我们把上面得出的式子移项,变成 d b d a 1 + c d_b\geq d_{a-1}+c ,于是我们就可以在 a 1 a-1 b b 中建一条长度为 c c 的边。

由于 d d 是有联系的,我们还发现两个条件 d i d i 1 > = 0 ; d i 1 d i > = 1 d_i-d_{i-1}>=0;d_{i-1}-d_i>=-1

按照这样建图后,根据 d b d a 1 + c d_b\geq d_{a-1}+c ,我们就可以跑最长路求出 d d

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>

int n, tot, s = 50000, t;
int head[50001], next[150001], ver[150001], edge[150001], v[50001], d[50001];

void add(int u, int v, int w) {
	ver[++tot] = v;
	next[tot] = head[u];
	edge[tot] = w;
	head[u] = tot;
}

void spfa() {
	std::queue<int> q;
	memset(d, -127 / 3, sizeof(d));
	v[s] = 1;
	d[s] = 0;
	q.push(s);
	while (q.size()) {
		int u = q.front();
		q.pop();
		v[u] = 0;
		for (int i = head[u]; i; i = next[i]) {
			int to = ver[i];
			if (d[to] < d[u] + edge[i]) {
				d[to] = d[u] + edge[i];
				if (!v[to]) {
					v[to] = 1;
					q.push(to);
				}
			}
		}
	}
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		int x, y, z;
		scanf("%d %d %d", &x, &y, &z);
		s = std::min(s, x - 1);
		t = std::max(t, y);
		add(x - 1, y, z);
	}
	for (int i = s + 1; i <= t; i++) {
		add(i, i - 1, -1);
		add(i - 1, i, 0);
	}
	spfa();
	printf("%d", d[t]);
}

猜你喜欢

转载自blog.csdn.net/SSL_hzb/article/details/88872940