[bsoj1271] 序列长度


题目描述

有一个整数序列,我们不知道她的长度是多少(序列中整数的个数),但我们知道在某些区间中至少有多少个整数,用区间 [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=aibitjci

Si=j=1itj

因此
SbjSai1ci(i=1,2,...,n)

因为tj只能为1或0,所以Si一定比Si-1大且至多大1
故有
SiSi10(1in)

Si1Si1(1in)

SbSa1ci

用差分约束跑一次最长路即可解决


源代码

贪心策略

#include
#include
#include
#include
#include
#include
#include
#include
#include
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.yint 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<return 0;
}

差分约束

#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
    vectoredges;
    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; iint 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]//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;
}

你可能感兴趣的:(差分约束,最短路径,贪心)