POJ2376(Cleaning Shifts)数据结构优化DP(线段树+DP)

Cleaning Shifts

Time Limit: 1000MS Memory Limit: 65536K

农民约翰正在指挥他的N头牛进行清理工作。
他将一天划分为了T个班次(1~T)。
每头牛都只能在一天中的某一个时间段内进行不间断的工作。
你需要帮助约翰排列出一个合理的奶牛的清理班次,使得每个班次都有奶牛在进行清理,而且动用的奶牛数量可以尽可能的少。

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

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

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

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

数据范围
1≤N≤250001≤N≤25000,
1≤T≤1061≤T≤106
输入样例:
3 10
1 7
3 6
6 10
输出样例:
2
解题思路:要清理从1到t的班次,首先定义边界条件f[0]=0,其余定义为正无穷。将所有的班次优先按从左边界从小到大排序前提下对左边界从小到大排序,对于对于班次 [ a, b ] 寻找f[a-1~b]最小值 f[b]=min(f[k])(a-1<=k<=b)+1,对于f数组通过线段树来维护。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 25001
#define ll long long
using namespace std;
int INF=1e9;
struct Node
{
     int minn;
     int l,r;

}t[1000000*4],a[N];

void bulid(int p,int l,int r){
    t[p].l=l,t[p].r=r;
    t[p].minn=INF;
    if(l==r){
        t[p].minn=INF;
        return ;
    }
    int mid=(l+r)/2;
    bulid(p*2,l,mid);
    bulid(p*2+1,mid+1,r);

}

int query(int p,int l,int r){
    if(l<=t[p].l&&r>=t[p].r){
        return t[p].minn;
    }
    int mid=(t[p].l+t[p].r)/2;
    int val=INF;
    if(l<=mid) val=min(val,query(p*2,l,r));
    if(r>mid) val=min(val,query(p*2+1,l,r));
    return val;
}

void change(int p,int x,int val){
    if(t[p].l==t[p].r) {
        t[p].minn=min(val,t[p].minn);//!!!重点,如果当前要修改的数字比之前的要大,则不修改!!!
        return;
    }
    int mid=(t[p].l+t[p].r)/2;
    if(x<=mid) change(p*2,x,val);
    else  change(p*2+1,x,val);
    t[p].minn=min(t[p*2].minn,t[p*2+1].minn);
}

bool cmp(Node x,Node y)
{
    if(x.l!=y.l) return x.l<y.l;
    return x.r<y.r;

}

int main()
{
    int n,t;
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].l,&a[i].r);
    } 
    sort(a+1,a+1+n,cmp); 
    bulid(1,0,1000007);
    change(1,0,0);
    for(int i=1;i<=n;i++){
        change(1,a[i].r,query(1,a[i].l-1,a[i].r)+1);
    }
    int  ans=query(1,t,t);
    if(ans>=INF) cout<<"-1"<<endl;
    else{
        cout<<ans<<endl;
    }
} 
带另一组样例
/*
20 1000
1 100
2 200
201 350
350 351
351 400
400 600
500 700
700 805
803 899
900 999
201 340
800 850
1000 1000
700 800
650 700
600 650
702 703
701 702
700 701
800 825

输出 10
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值