P1280 尼克的任务
没有采用其他题解中按时间来dp的方法,还是传统的按任务来dp。显然每个任务是一个区间,区间不能重叠是基础,同时两个区间可以形成dp关系,必须要求区间之间的区域不能有其他的区间存在。
dp[i]表示当我们执行第i个任务时可获得的最大的休息时间。注意dp数组应初始化为负无穷。
算法步骤: (1)先读入数据,并更改成区间形式,按区间左端点排序。另外用一个桶来记录每个时间点是否有区间的左端点存在。
(2)对第一个可能的任务进行dp初始化,显然只有时间最早的若干个任务可以作为dp的起点。
(3)从第二个任务开始dp。dp条件:前面的任务结束时间早于i任务开始时间,同时利用桶的前缀和数组判断这两个时间点间是否有其他任务,如果两个条件都满足则可以dp。 for(i=2; i<=k; i++) for(j=i-1; j>=1; j--) if(a[j].r<a[i].l&&sum[a[i].l-1]-sum[a[j].r]==0) dp[i]=max(dp[i],dp[j]+a[i].l-a[j].r-1);
(4)枚举最后一个任务计算最大休息时间,最后一个任务结束后(如样例)可能还有剩余时间。
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,k,dp[10005],sum[10005],ans;
struct node
{
int l,r;
bool operator<(const node y)const
{
return l<y.l;
}
} a[10005];
int main()
{
int i,j;
memset(dp,-127/3,sizeof(dp));
cin>>n>>k;
for(i=1; i<=k; i++)
{
cin>>a[i].l>>a[i].r;
a[i].r=a[i].l+a[i].r-1;
sum[a[i].l]++;
}
for(i=1; i<=n; i++)
sum[i]=sum[i-1]+sum[i];
sort(a+1,a+k+1);
for(i=1; i<=k; i++)
if(i==1||a[i].l==a[1].l)
dp[i]=a[1].l-1;
for(i=2; i<=k; i++)
for(j=i-1; j>=1; j--)
if(a[j].r<a[i].l&&sum[a[i].l-1]-sum[a[j].r]==0)
dp[i]=max(dp[i],dp[j]+a[i].l-a[j].r-1);
for(i=1; i<=k; i++)
if(sum[n]-sum[a[i].r]==0)
ans=max(ans,dp[i]+n-a[i].r);
cout<<ans;
return 0;
}