POJ 1201 Intervals

题目链接

题目大意:

给定 n 个区间 [ai,bi]和 n 个整数 ci。

你需要构造一个整数集合 Z,使得∀i∈[1,n] ,Z 中满足 ai ≤ x ≤ bi 的整数 x 不少于 ci 个。

求这样的整数集合 Z 最少包含多少个数。

思路:

定义d[ x ]表示 0到x最少选择多少个数字,则有 d[bi] - d[ai - 1] >= ci,变形后可得 d[bi] >= d[ai - 1] + ci,最短路径算法中的三角不等式,因此本题目可以用差分约束来解决

除了上述条件外,还有两个隐含的条件,因为d[x]表示的是从0开始到x最少选择几个数字,所以0 <= d[x + 1] - d[x] <= 1

因此我们又得到了两个不等式,用上述不等式建图之后,跑一遍最长路就ok了(当然最短路也可以,最短路的建图和源点汇点的选择会与最长路有所不同)

重点:

如果求x3 - x1的最大值,就可以将上述要求化成x3 - x1 <= t,求 t 的值,而x3 <= x1 + t是最短路中的松弛操作,相当于求x1 到 x3的最短路径,反之,如果求最小值,就是x3 - x1 >= t,相当于x3 >= x1 + t,相当于从x1 到 x3的最长路。

同理,也可以将最大值理解为,x3 - x1 <= t  --> x1 - x3 >= -t,即x3 到 x1的最长路,但是这样求出来的是 -t,我们要求 t ,所以求其相反数即可

最长路code

#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
const int N = 51000 * 3;
int head[N], nex[N], to[N], edge[N];
int d[N];
int cnt, c[N], n;
bool v[N];
struct SPFA {
	SPFA() {
		mem(head, -1);
		mem(nex, -1);
		mem(to, -1);
		cnt = 0;
		mem(c, 0);
		mem(v, 0);
		mem(d, 0x3f);
		for (int i = 0; i < N; i++)d[i] = -d[i];
	}
	void init() {
		SPFA();
	}
	void add(int x, int y, int z) {
		++cnt;
		to[cnt] = y;
		edge[cnt] = z;
		nex[cnt] = head[x];
		head[x] = cnt;
	}
	int spfa(int be, int en) {
		c[be]++;
		d[be] = 0;
		v[be] = 1;
		queue<int> q;
		q.push(be);
		bool f = 1;
		while (!q.empty()) {
			int t = q.front();
			q.pop();
			v[t] = 0;
			if (c[t] > n) {
				f = 0;
				break;
			}
			c[t]++;
			for (int i = head[t]; i != -1; i = nex[i]) {
				int y = to[i];
				int dist = edge[i];
				if (d[y] < d[t] + dist) {
					d[y] = d[t] + dist;
					if (!v[y]) {
						v[y] = 1;
						q.push(y);
					}
				}
			}
		}
		if (f)
			return d[en];
		else
			return -1;
	}
}sp;
int main()
{
	sp.init();
	ios::sync_with_stdio(0);
	cin >> n;
	int be = 0x3f3f3f3f;
	int en = -1;
	for (int i = 0; i < n; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		// y >= (x - 1) + ci
		sp.add(x, y + 1, z);
	}
	for (int i = 0; i < 50002; i++) {
		sp.add(i, i + 1, 0);
		sp.add(i + 1, i, -1);
	}
	cout << sp.spfa(0, 50001) << "\n";
	return 0;
}

最短路code 

/*
 * Test2
 */
#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
const int N = 51000 * 3;
int head[N], nex[N], to[N], edge[N];
int d[N];
int cnt, c[N], n;
bool v[N];
struct SPFA {
	SPFA() {
		mem(head, -1);
		mem(nex, -1);
		mem(to, -1);
		cnt = 0;
		mem(c, 0);
		mem(v, 0);
		mem(d, 0x3f);
		// for (int i = 0; i < N; i++)d[i] = -d[i];
	}
	void init() {
		SPFA();
	}
	void add(int x, int y, int z) {
		++cnt;
		to[cnt] = y;
		edge[cnt] = z;
		nex[cnt] = head[x];
		head[x] = cnt;
	}
	int spfa(int be, int en) {
		c[be]++;
		d[be] = 0;
		v[be] = 1;
		queue<int> q;
		q.push(be);
		bool f = 1;
		while (!q.empty()) {
			int t = q.front();
			q.pop();
			v[t] = 0;
			if (c[t] > n) {
				f = 0;
				break;
			}
			c[t]++;
			for (int i = head[t]; i != -1; i = nex[i]) {
				int y = to[i];
				int dist = edge[i];
				if (d[y] > d[t] + dist) {
					d[y] = d[t] + dist;
					if (!v[y]) {
						v[y] = 1;
						q.push(y);
					}
				}
			}
		}
		if (f)
			return d[en];
		else
			return -1;
	}
}sp;
int main()
{
	sp.init();
	ios::sync_with_stdio(0);
	cin >> n;
	int be = 0x3f3f3f3f;
	int en = -1;
	for (int i = 0; i < n; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		// y >= (x - 1) + ci
		// sp.add(x, y + 1, z);
		sp.add(y + 1, x, -z);
	}
	for (int i = 0; i < 50002; i++) {
		sp.add(i, i + 1, 1);
		sp.add(i + 1, i, 0);
	}
	cout << -sp.spfa(50001, 0) << "\n";
	return 0;
}

 

posted @ 2020-01-20 22:15  correct  阅读(111)  评论(0)    收藏  举报