题目大意
有一个序列,题目用n个整数组合 [ai,bi,ci] 来描述它, [ai,bi,ci] 表示在该序列中处于 [ai,bi] 这个区间的整数至少有 ci 个。如果存在这样的序列,请求出满足题目要求的最短的序列长度是多少。如果不存在则输出 -1。 (0≤ai≤bi≤50000,1≤ci≤bi−ai+1)
分析
关于一个区间里和的数目的问题很容易联想到用 sum[i] 表示从起点到i的总的和,那么 sum[b]−sum[a−1] 就表示区间 [a,b] 的和了。
再根据题目的约束条件 sum[bi]−sum[ai−1]≥ci ,
还需要注意的地方是除了上面这个约束条件,题目还隐含的约束条件就是 0≤sum[i]−sum[i−1]≤1
转化之后就是
由于题目中 ai 最小是0,所以在输入的时候把 a,b 都加上1避免数组-1越界
这样就变成了差分约束系统的问题了。
bellman-ford的松弛操作的目的是为了让点的距离满足
dis[v]<=dis[u]+w[u][v]
这一约束条件,转化一下就变成了
dis[u]−dis[v]≥−w[u][v]
,这样就和常见差分约束问题约束条件的形式
(a−b≥c)
一样了,上面的
sum
数组也就对应与图中的距离。
差分约束系统
这里简单写一下差分约束系统的思路,约束条件 (a−b≥c) 意思是a至少要比b大c.
而在路径问题中的边(x指向y,权值为w)的含义是y的距离最多比x大w.
“y的距离最多比x大w” (dist[y]≤dist[x]+w) n ⇐⇒ “x至少要比y大-w” (dist[x]≥dist[y]−w)
所以约束条件 (a−b≥c) :a至少要比b大c等价于 “b的距离最多比a大-c”也就是a指向b权值为-c
可以通过大于的传递性得到一个变量 Xi 比另一个变量 Xj 至少大多少也就是 max(Xi−Xj)=max(∑c) ,但路径上的权值加起来是 (−∑c) 要求 (∑c) 的最大值就是求路径 (−∑c) 的最小值,最短路算法计算的过程中 Xi 作为源点。
代码
/*
有向图
前向星存边
这道题没有成环的情况
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
using namespace std;
const int INF=0x7fffffff;//无穷大
struct Edge
{
int to;
int next;
int w;
}edge[500005];
int edgecount;
int head[50005];
int dis[50005];
bool vis[50005];
void Init_edge()
{
memset(head,-1,sizeof(head));
edgecount=0;
}
void Add_Edge(int u,int v,int w)
{
edge[++edgecount].to=v;
edge[edgecount].w=w;
edge[edgecount].next=head[u];
head[u]=edgecount;
}
void Spfa(int n)
{
memset(vis,0,sizeof(vis));
for(int i=0;i<=n;i++)dis[i]=INF;
dis[n]=0;
vis[n]=1;
queue<int> Q;
Q.push(n);
int cnt=1;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int k=head[u];k!=-1;k=edge[k].next)
{
int t=dis[u]+edge[k].w;
if(dis[edge[k].to]>t)
{
dis[edge[k].to]=t;
if(vis[edge[k].to]==1)continue;
Q.push(edge[k].to);
vis[edge[k].to]=1;
}
}
vis[u]=0;
}
cout<<-dis[0]<<endl;
}
int main()
{
int n;
int a,b,c;
int maxn;
while(scanf("%d",&n)!=EOF && n)
{
Init_edge();
maxn=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a,&b,&c);
a++;b++;
maxn=max(b,maxn);
Add_Edge(b,a-1,-c);
}
for(int i=1;i<=maxn;i++)
{
Add_Edge(i,i-1,0);
Add_Edge(i-1,i,1);
}
Spfa(maxn);
}
return 0;
}