题目描述
有一个整数序列,我们不知道她的长度是多少(序列中整数的个数),但我们知道在某些区间中至少有多少个整数,用区间 [ai,bi,ci]来描述它,[ai,bi,ci]表示在该序列中处于[ai,bi]这个区间的整数至少有ci个。现在给出若干个这样的区间,请你求出满足条件的最短的序列长度是多少。如果不存在则输出 -1。
输入格式
第一行包括一个整数n(n<=1000),表示区间个数;
以下n行每行描述这些区间,第i+1行三个整数ai,bi,ci,由空格隔开,其中0<=ai<=bi<=1000 而且 1<=ci<=bi-ai+1。
输出格式
一行,输出满足要求的序列的长度的最小值。
样例数据
样例输入
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
样例输出
6
题目分析
经典贪心问题,也可以用差分约束做。
用ti=1或0表示i是否存在于序列中
约束条件即为:
∑j=aibitj≥ci
设Si=∑j=1itj
因此Sbj−Sai−1≥ci(i=1,2,...,n)
因为tj只能为1或0,所以Si一定比Si-1大且至多大1
故有
Si−Si−1≥0(1≤i≤n)
Si−1−Si≥−1(1≤i≤n)
Sb−Sa−1≥ci
用差分约束跑一次最长路即可解决
源代码
贪心策略
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
int b[100005],n,sum=0;
struct node {
int x,y,z;
} a[200005];
bool cmp(node a,node b) {
return a.y<b.y;
}
int main() {
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i].x>>a[i].y>>a[i].z;
sort(a+1,a+n+1,cmp);
for(int i=1; i<=n; i++) {
for(int j=a[i].x; j<=a[i].y; j++)
if(b[j]!=0)a[i].z--;
for(int j=a[i].y; a[i].z>0; j--)
if(b[j]==0) {
sum++;
b[j]=1;
a[i].z--;
}
}
cout<<sum<<endl;
return 0;
}
差分约束
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=20005;
struct Edge {
int from,to,dist;
} E[50005];
struct Difference_Constraints { //差分约束系统
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
bool inque[maxn];
int dist[maxn],used[maxn],path[maxn];
int ans[maxn]; //ans表示不等式组答案
void init(int n) {
this->n=n;
edges.clear();
for(int i=1; i<=n; i++)G[i].clear();
}
void AddEdge(int from,int to,int dist) {
edges.push_back((Edge) {
from,to,dist
});
m=edges.size();
G[from].push_back(m-1);
}
void insert(int x,int y,int v,bool flag) { //x-y<=v (flag=0),x-y>=v (flag=1)
if(flag==0)AddEdge(y,x,v);
if(flag==1)AddEdge(y,x,-v);
}
bool spfa(int s) {
for(int i=1; i<=n; i++)dist[i]=0x7fffffff/2;
memset(inque,0,sizeof(inque));
deque<int>Q;
Q.push_back(s);
dist[s]=0;
path[s]=s;
inque[s]=1;
used[s]++;
while(!Q.empty()) {
int Now=Q.front();
Q.pop_front();
inque[Now]=0;
for(int i=0; i<G[Now].size(); i++) {
Edge& e=edges[G[Now][i]];
int Next=e.to;
if(dist[Next]>dist[Now]+e.dist) {
dist[Next]=dist[Now]+e.dist;
path[Next]=Now;
if(!inque[Next]) {
used[Next]++;
if(used[Next]==edges.size())return false; //负权回环
if(!Q.empty()&&dist[Next]<dist[Q.front()])Q.push_front(Next); //SLF优化
else Q.push_back(Next);
inque[Next]=1;
}
}
}
}
return true;
}
bool main(int Start,bool flag) { //求出正整数解
if(spfa(Start)==0)return false;
int Min=0x7fffffff/2;
if(flag==1) { //最长路
for(int i=1; i<=n; i++)dist[i]*=-1;
}
for(int i=1; i<=n; i++)Min=min(Min,dist[i]); //转为正数
for(int i=1; i<=n; i++)ans[i]=dist[i]-Min;
return true;
}
void Output() {
for(int i=1; i<=n; i++)printf("%d\n",ans[i]);
}
};
Difference_Constraints dc; //全程大于符
/*
t[i]表示i是否存在序列中
s[i]=t[1]+...+t[i]
约束条件:
s[y]-s[x-1]>=c[i]
s[i]-s[i-1]>=0
s[i-1]-s[i]>=-1
*/
int n,m;
int main() {
m=Get_Int();
for(int i=1; i<=m; i++) {
int x=Get_Int(),y=Get_Int(),v=Get_Int();
E[i].from=x;
E[i].to=y;
E[i].dist=v;
n=max(n,max(x,y));
}
dc.init(n);
for(int i=1; i<=n; i++) {
dc.insert(i,i-1,0,1);
dc.insert(i-1,i,-1,1);
}
for(int i=1; i<=m; i++) {
int x=E[i].from,y=E[i].to,v=E[i].dist;
dc.insert(y,x-1,v,1);
}
if(dc.main(0,1)==0) {
puts("-1");
return 0;
}
printf("%d\n",dc.ans[n]);
return 0;
}