清理班次(dp&&线段树)

29 篇文章 0 订阅

农民约翰正在指挥他的N头牛进行清理工作。

他将一天划分为了T个班次(1~T)。

每头牛都只能在一天中的某一个时间段内进行不间断的工作。

你需要帮助约翰排列出一个合理的奶牛的清理班次,使得每个班次都有奶牛在进行清理,而且动用的奶牛数量可以尽可能的少。

输入格式

第1行:两个空格隔开的整数N和T。

第2..N+1行:第i+1行包含两个整数,分别表示第i头牛可以进行工作的开始时间和结束时间。

输出格式

输出一个整数,表示在每个班次都有奶牛清理的情况下,所需的奶牛最小数量。

如果无法做到每个班次都有奶牛清理,则输出-1。

数据范围

1≤N≤25000,
1≤T≤106

输入样例:

3 10
1 7
3 6
6 10

输出样例:

2

思路:本题可以转化为求:将[1,t]这个区间完全覆盖的最小的区间个数 

状态表示:

用f[i]表示在用i位置左边的区间将[1,i]覆盖的所有方案中的最小区间个数

状态计算:

将集合按最后一个区间的不同划分为若干子集,因为最后一个区间可以看成是固定的,只需要区分动态的前面的已经覆盖的区间的右端点k,且k的范围为[l-1,r].

所以取这些子集的min即为以当前最后一个区间为[l,r]的方案的覆盖的最小个数,即:f[r]=min(f[k])

因为数据范围较大,所以可以用线段树来维护覆盖一个区间的最小区间个数。

注:初始时,将个数设为inf,如果某一点i不是任何一个方案的最后一个区间的右端点,说明没有覆盖到当前i的方案,所以无解。

完整代码:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn=1e6+5,inf=1e8;

struct Range
{
    int l,r;
    bool operator< (const Range &t)const
    {
        return r<t.r;
    }
}range[maxn];

struct
{
    int l,r,v;
}tree[maxn<<2];

int n,t;

void pushup(int p)
{
    tree[p].v=min(tree[p<<1].v,tree[p<<1|1].v);
}

void build(int p,int l,int r)
{
    tree[p]={l,r,inf};
    if(l==r) return;
    int mid=l+r>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
}

void update(int p,int k,int v)
{
    if(tree[p].l==tree[p].r){
        tree[p].v=min(tree[p].v,v);
        return;
    }
    int mid=tree[p].l+tree[p].r>>1;
    if(k<=mid) update(p<<1,k,v);
    else update(p<<1|1,k,v);
    pushup(p);
}

int query(int p,int l,int r)
{
    if(tree[p].l>=l&&tree[p].r<=r){
        return tree[p].v;
    }
    int mid=tree[p].l+tree[p].r>>1;
    int res=inf;
    if(l<=mid) res=query(p<<1,l,r);
    if(r>mid) res=min(res,query(p<<1|1,l,r));
    return res;
}

int main()
{
    cin>>n>>t;
    build(1,0,t);
    for(int i=0;i<n;i++){
        cin>>range[i].l>>range[i].r;
    }
    sort(range,range+n);
    update(1,0,0);
    for(int i=0;i<n;i++){
        int l=range[i].l,r=range[i].r;
        int v=query(1,l-1,r-1)+1;//dp当前v=min(f(k)) k从l-1到r-1,再加上当前[l,r]这一个
        update(1,r,v);//用覆盖当前[1,r]的最小区间个数v(f[r]=v),更新覆盖r点的区间的信息
    }
    int res=query(1,t,t);
    if(res==inf) cout<<-1<<endl;
    else cout<<res<<endl;
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值