题目描述
尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。
尼克的一个工作日为 𝑛 分钟,从第 1 分钟开始到第 𝑛 分钟结束。当尼克到达单位后他就开始干活,公司一共有 𝑘 个任务需要完成。如果在同一时刻有多个任务需要完成,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去完成,假如某些任务开始时刻尼克正在工作,则这些任务也由尼克的同事完成。如果某任务于第 𝑝 分钟开始,持续时间为 𝑡 分钟,则该任务将在第 (𝑝+𝑡−1) 分钟结束。
写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间。
输入格式
输入数据第一行含两个用空格隔开的整数 𝑛 和 𝑘。
接下来共有 𝑘 行,每一行有两个用空格隔开的整数 𝑝 和 𝑡,表示该任务从第 𝑝 分钟开始,持续时间为 𝑡 分钟。
输出格式
输出文件仅一行,包含一个整数,表示尼克可能获得的最大空暇时间。
输入输出样例
输入 #1
15 6 1 2 1 6 4 11 8 5 8 1 11 5
输出 #1
4
说明/提示
数据规模与约定
- 对于 100% 的数据,保证 1≤𝑛≤104,1≤𝑘≤104,1≤𝑝≤𝑛,1≤𝑝+𝑡−1≤𝑛。
题目传送门
题目解析
观察题目
题目给我们尼克的上班时间和任务总数以及任务开始时间和持续时间,要求我们让尼克获得最大的空闲时间(尼克可能很爱摸鱼),在这个时间点只有一条任务且尼克处于空闲状态的情况下,必须要做这个任务,如有多条任务,那尼克就可以任选一个来做了,当然,他不可以不做。
观察样例
15 6
1 2
1 6
4 11
8 5
8 1
11 5
尼克可以做任务2,第一分钟到第六分钟做,第七分钟空闲,第八分钟到第十二分钟做任务四,第十三分钟不干,第十四分钟不干,第十五分钟也不干,共休息4分钟
解题算法
这一道题想用贪心是不行的,因为时间最短不代表他总休息时间最长,所以我们考虑用dp,但是,从前往后dp显然是有后效性的,学dp不能死学死用,要学会活学活用,我们可以尝试从后往前dp,只要这一点没有任务,那么空闲时间加一,有的话就看一看哪种任务所获得的空闲时间最多。
ACcode
这里声明,抄题解是不好的行为,请各位读懂代码在自己写出
#include<bits/stdc++.h>
using namespace std;
struct renwu{
int p;
int t;
}a[10005];
int n,k,dp[10055];
int main(){
cin>>n>>k;
for(int i=1;i<=k;i++){
cin>>a[i].p>>a[i].t;//输入
}
for(int i=1;i<=k;i++){
for(int j=1;j<i;j++){
if(a[j].p>a[i].p){//排序,为后面计算方便
swap(a[j].p,a[i].p);
swap(a[j].t,a[i].t);
}
}
}
int j=k;
for(int i=n;i>0;i--){
if(a[j].p!=i){//没有任务
dp[i]=dp[i+1]+1;//空闲时间加1
}
else{
//如果这个时间点有任务
while(a[j].p==i){//计算这个时间点哪一个任务空闲最多
dp[i]=max(dp[i],dp[i+a[j].t]);//因为题目有p+t-1这个条件,所以要减一
j--;//下一任务
}
}
}
cout<<dp[1];
}