题目
样例输入
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
样例输出
6
思路
本题要求需要用差分约束,差分约束的理解是个难点。
对于差分约束中的每一个不等式约束 𝑥𝑖 − 𝑥𝑗 ≤ 𝑐𝑘 都可以移项变形为 𝑥𝑖 ≤ 𝑐𝑘 + 𝑥𝑗,对应了最短路问题的松弛操作:
即保证了dis[ i ] <= dis[ j ] + ck,根据这个特征,可以将不等式约束𝑥𝑖 − 𝑥𝑗 ≤ 𝑐𝑘 转换为 j -> i 的一条边,权重为k。
最小值问题:
如图(图转载自:https://www.cnblogs.com/zzz-hhh/p/11200893.html)
将(1)式与(2)式合并,得到C - A >= (a + c),通过因为不等式符号为>=,对应spfa求最长路问题,结果即为 max(a + c,b),即C - A的最小值。
对于本题:
设sum[x]为x点在[0,x]区间内选的点数,对于每个区间[a,b]内选c个点,则有sum[a]-sum[b-1]>=c,为了使sum有意义,对于每个数i,存在0<=sum[i+1]-sum[i]<=1;
这样得到了该题所有的不等式,将其都转换为>=的不等式,接下来则使用差分模型即可。
最终输出所有区间最右端点ans的sum[ans]。
构造不等式组:
对第 i 个区间 ai [𝑎𝑖, 𝑏𝑖] ,需要满足 sumbi - sumai >= ci,又因为需要保证sum有意义,0 <= sum[ i ] - sum[ i - 1] <= 1。
为什么要满足第二个条件呢,我想应该是一下原因:
代码
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdio>
#define MAXN 50020
#define inf 100000000
using namespace std;
queue<int> q;
int dis[MAXN];
bool inq[MAXN];
struct Edge
{
int u, v, w, next;
}Edge[200010];
int head[MAXN];
int total, n, maxx, a, b, c;
void init()
{
total = 0;
for (int i = 0; i < MAXN; i++)
head[i] = -1;
}
void addEdge(int uu, int vv, int ww)
{
Edge[total].u = uu;
Edge[total].v = vv;
Edge[total].w = ww;
Edge[total].next = head[uu];
head[uu] = total++;
}
void spfa(int s, int n)
{
//cout << "in" << endl;
while (!q.empty()) q.pop();//先清空堆
//初始化
for (int i = 0; i <= n; i++)
{
dis[i] = -inf;
inq[i] = 0;
}
dis[s] = 0;
inq[s] = 1;
q.push(s);
while (!q.empty())
{
int x = q.front();//最小边邻接的点
q.pop();
inq[x] = 0;
for (int i = head[x]; i != -1; i = Edge[i].next)
{
int y = Edge[i].v;
//cout << "y:" << y << endl;
int w = Edge[i].w;
if (dis[y] < dis[x] + w)
{
dis[y] = dis[x] + w;
if (inq[y] == 0)
{
q.push(y);
inq[y] = 1;
}
}
}
}
}
int main()
{
scanf("%d", &n);
init();
maxx = 0;
for (int i = 0; i < n; i++)
{
scanf("%d%d%d", &a, &b, &c);
if (maxx <= b) maxx = b + 1;
addEdge(a, b + 1, c);
}
for (int i = 0; i <= maxx; i++)
{
addEdge(i, i - 1, -1);
addEdge(i - 1, i, 0);
}
spfa(0, maxx+1);
printf("%d", dis[maxx]);
//system("pause");
}