Week8:区间选点——差分约束思路

题目内容
给定一个数轴上的 n 个区间,要求在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点。

输入格式
输入第一行一个整数 n 表示区间的个数,接下来的 n 行,每一行两个用空格隔开的整数 a,b 表示区间的左右端点。1 <= n <= 50000, 0 <= ai <= bi <= 50000 并且 1 <= ci <= bi - ai+1。

输出格式
输出一个整数表示最少选取的点的个数。

输入样例

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

输出样例

6

备注
本题的局部贪心解法请移步:https://blog.csdn.net/qq_44506233/article/details/104702237

解题思路
使用差分约束的角度来分析这道题。
关于差分约束的讲述,请在本站中自行搜索“差分约束”。

题目要求:

  • 在数轴上选取最少的点使得第 i 个区间 [ai, bi] 里至少有 ci 个点

即,如果我们设置数组sum,其中sum[i]意为从零点到点i这个区间中所有的点的数目。那么对于上述的要求,我们可以得到:

  • sum[bi]-sum[ai-1] >= ci

除此之外,题目中还有一个隐藏条件:

  • 对于某个位置,只有两种情况:
  • 1.这个位置上没有点
  • 2.这个位置上有点

那么如何转换成不等式的形式呢?

  • sum[i]-sum[i-1] >= 0
  • sum[i]-sum[i-1] <= 1

而由于题目中要求的是整个区间范围内所取的点的最少数目,即当整个区间的最右端点为b时,需要求:

  • sum[b]>=T

这里这个T就是我们所要求的答案。
把所有的不等式转换成>=形式跑最长路即可。

Tips:最后的T的那个不等式不符合我们解差分约束的不等式的格式,所以我们可以人为把输入的所有的点都+1,然后把sum[0]设置为0即可,此时的答案就是:

  • sum[b+1]-sum[0] >=T

下面给出代码:

#include <iostream>
#include <cstring>
#include <queue>

const int INF = 0x3f3f3f3f;
const int maxn = 500005;

using namespace std;

int n, mostright, cur;
int head[maxn], visit[maxn], sum[maxn];

struct Node
{
	int v, w, next;
}edge[maxn];

void addEdge(int u, int v, int w)
{
	edge[cur].v = v;
	edge[cur].w = w;
	edge[cur].next = head[u];
	head[u] = cur;
	cur++;
}

void SPFA()
{
	queue<int>q;
	q.push(0);
	sum[0] = 0;
	visit[0] = 1;
	while (!q.empty())
	{
		int now = q.front();
		q.pop();
		visit[now] = 0;
		for (int i = head[now]; i != -1; i = edge[i].next)
		{
			int v = edge[i].v;
			int w = edge[i].w;
			if (sum[v] < sum[now] + w)
			{
				sum[v] = sum[now] + w;
				if (!visit[v])
				{
					q.push(v);
					visit[v] = 1;
				}
			}
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	memset(visit, 0, sizeof visit);
	memset(head, -1, sizeof head);
	mostright = 0;
	cur = 0;

	cin >> n;
	for (int i = 0, a, b, c; i < n; i++)
	{
		cin >> a >> b >> c;
		addEdge(a, b + 1, c);
		if (b + 1 > mostright)
		{
			mostright = b + 1;
		}
	}

	for (int i = 0; i <= mostright; i++)
	{
		sum[i] = -INF;
		addEdge(i, i + 1, 0);
		addEdge(i + 1, i, -1);
	}

	SPFA();

	cout << sum[mostright] << endl;
}

原创文章 52 获赞 7 访问量 1681

猜你喜欢

转载自blog.csdn.net/qq_44506233/article/details/105578059
今日推荐