给定 n 个区间 [ai,bi] 和 n 个整数 ci。
你需要构造一个整数集合 Z,使得 ∀i∈[1,n],Z 中满足 ai≤x≤bi 的整数 x 不少于 ci 个。
求这样的整数集合 Z 最少包含多少个数。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含三个整数 ai,bi,ci。
输出格式
输出一个整数表示结果。
数据范围
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
典型的差分约束问题若不懂差分约束的可以看看这篇:(15条消息) 《图论:差分约束算法详解 + 算法证明》+ 模板题:糖果_wsh1931的博客-CSDN博客
首先他求的是最小值,所以我们要用最长路
假设:s[i]为从1 - i 中选择了多少个数
题目给的数据范围是从0 - 5000我们为了遍历到所有点,即建立超级源点可以将0 - 50000映射成1 - 50001;
由题意我们可以得到上述结论
1: s[0] = 0
2: s[i] - s[i - 1] <= 1(即第i个数最多只能选一个)-> s[i - 1] >= s[i] - 1;
3: s[b] - s[a - 1] >= c (a, b, c)为题目输入的从区间[a, b]中选择的数不少于c个 -> s[b] >= s[a - 1] + c
4: s[i] >= s[i - 1] (即从前i个数中选择的数比从前i - 1个数中选择的数多)
又因为答案肯定有解,所以不需要判断是否无解
然后我们验证一下从源点出发是不是可以遍历所有点由结论4可以我们可以从0 -> 1. 1-> 2......n - 1 -> n因此可以遍历所有点
建图的边数:结论2, 3, 4所需要建立的边数各位N所以总共需要建立3 * N条边
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 50010, M = 3 * N;
int n;
bool st[N];
int dist[N];
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx;
idx ++ ;
}
void spfa()//求最小值用最长路
{
memset(dist, -0x3f, sizeof dist);
dist[0] = 0;
queue<int> q;
q.push(0);
while (q.size())
{
auto t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] < dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
}
int main()
{
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i < N; i ++ )//结论2,4;
{
add(i, i - 1, -1);
add(i - 1, i, 0);
}
int res = 0;
while (n -- )
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
a ++ , b ++ ;//将0 - 50000映射成1 - 50001
res = max(res, b);//求出前res个数中至少选择了多少个数
add(a - 1, b, c);
}
spfa();
cout << dist[res] << endl;//前res个数中共选择了多少个数
return 0;
}