果园守望者

来源:互联网 发布:恒生交易软件 编辑:程序博客网 时间:2024/05/11 06:22

Description

重庆有很多区县都盛产水果,每当到了水果成熟的时节,何老板就会看准商机,推出了一项名为“果园守望者”的服务。该服务很简单,就是何老板安排人手去为你看守果园,帮你驱赶鸟兽或者小偷。 
最近,何老板又签下了一个看守合同,该合同需要何老板派人看守一个果园,时间是从第A天起一直到第B天。在这B-A+1天里,要求每天至少有一个人在看守果园。 
何老板手下共有N个员工。每个员工都对自己的工作时间和报酬有一定的要求,比如员工甲只在T1..T2这段时间工作,并要求S1元的报酬;员工乙只在T3..T4这段时间工作,并要求S2元的报酬...... 
请你帮助何老板安排一个工作时间表,使得从第A天到第B天每天至少有一个员工在看守果园,并且使得何老板支付的报酬总数尽可能少。

Input

第一行,三个空格间隔的整数N,A,B 
接下来N行,每行三个整数T1,T2,和S,表示对应员工愿意工作的起止时间和要求的报酬。

Output

一个整数,表示何老板需支付的最少报酬总数。如果无法安排员工完成工作,输出-1

Sample Input

3 0 40 2 33 4 20 0 1

Sample Output

5

Hint

1 <= N <= 10,000 
0 <= A <= B <= 90000 
A <= T1 <= T2 <= B 
0 <= S <= 500,000 
样例说明
安排第一个员工工作0,1,2三天 
安排第二个员工工作3,4两天 
就把从第0天到第4天这5天的看守工作完成了。


【分析】

        这道题明显是DP。定义状态数组:F[i]表示以i天结尾的最优值

        如果是不能交叉的覆盖,那么方程为F[T[i].b]=min(F[k])+T[i].w  k<=T[i].a-1;

        但是题目的意思是可以有覆盖的,那么只需要修改边界条件为 T[i].a-1<=k<=T[i].b (因为要完全覆盖,所以有下界)。

        修正后的方程:F[i]=min(F[k])+T[j].w   (i=T[j].b,T[j].a-1<=k<=T[j].b)。但是这样的话复杂度就会很高O(N*B),所以可以用线段树优化。即多加一个域dp来维护动归过程。(我的线段树是堆式线段树,代码有体现)


【代码】

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<ctime>#include<iostream>#include<algorithm>using namespace std;const int INF=1000000000;int N,A,B;struct wjj{int a,b,w;}T[10005];struct node{int L,R,dp;}Tree[400005];bool _cmp(wjj x,wjj y){return (x.a<y.a);}void _built(int id,int l,int r){int mid;Tree[id].L=l;Tree[id].R=r;Tree[id].dp=INF;if(l<r){mid=(l+r)>>1;_built((id<<1),l,mid);_built((id<<1)+1,mid+1,r);}}void _insert(int id,int r,int v){if(Tree[id].L==Tree[id].R)    Tree[id].dp=min(Tree[id].dp,v);else{int mid=(Tree[id].L+Tree[id].R)>>1;if(r<=mid) _insert((id<<1),r,v);else _insert((id<<1)+1,r,v);Tree[id].dp=min(Tree[id].dp,min(Tree[(id<<1)].dp,Tree[(id<<1)+1].dp));}}int _findans(int id,int l,int r){if(l<=Tree[id].L&&Tree[id].R<=r)    return Tree[id].dp;int mid=(Tree[id].L+Tree[id].R)>>1;int temp=INF;if(l<=mid) temp=min(temp,_findans((id<<1),l,r));if(mid<r) temp=min(temp,_findans((id<<1)+1,l,r));return temp;}void _init(){scanf("%d%d%d",&N,&A,&B);for(int i=1;i<=N;i++)    scanf("%d%d%d",&T[i].a,&T[i].b,&T[i].w);sort(T+1,T+1+N,_cmp);    //按工作开始时间由小到大排序 }void _solve(){int temp,ans;_built(1,A,B);_insert(1,A-1,0);     //初始化线段树,把A之前的时间所需费用初始化为0 for(int i=1;i<=N;i++){temp=_findans(1,T[i].a-1,T[i].b);_insert(1,T[i].b,temp+T[i].w);}ans=_findans(1,B,B);if(ans==INF)    printf("-1\n");else    printf("%d\n",ans);}int main(){_init();_solve();return 0;}


原创粉丝点击