题目描述
尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。
尼克的一个工作日为N分钟,从第一分钟开始到第N分钟结束。当尼克到达单位后他就开始干活。如果在同一时刻有多个任务需要完成,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去完成,假如某些任务开始时刻尼克正在工作,则这些任务也由尼克的同事完成。如果某任务于第P分钟开始,持续时间为T分钟,则该任务将在第P+T-1分钟结束。
写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间。
输入输出格式
输入格式:
输入数据第一行含两个用空格隔开的整数N和K(1≤N≤10000,1≤K≤10000),N表示尼克的工作时间,单位为分钟,K表示任务总数。
接下来共有K行,每一行有两个用空格隔开的整数P和T,表示该任务从第P分钟开始,持续时间为T分钟,其中1≤P≤N,1≤P+T-1≤N。
输出格式:
输出文件仅一行,包含一个整数,表示尼克可能获得的最大空暇时间。
输入输出样例
输入样例:
15 6
1 2
1 6
4 11
8 5
8 1
11 5
输出样例:
4
如何得到最优解,可以分拆子问题,数据量又这么大的题目当然是动态规划喽!想要求出最大空暇时间,可以分解成求解每个时间的最大空暇时间,于是考虑到每个没有起始任务的时间的最大空余时间就是下一分钟的最大空余时间加一;而有起始任务的时间( 如输入样例的4分钟就存在一个4分钟开始维持11分钟的任务 ),它的空余时间就是它任务结束时间的最大空余时间,如果一个时间存在多个开始任务,那么选取其中可以得到最大空余时间的任务!
解释一下样例的动态规划流程。因为无论当前时间有没有起始任务,用到的历史数据都是比当前时间大的时间,所以从最大时间开始计算。
15 -- 不存在起始任务,为16时间( 初始值0 )+1 -- 1
14 -- 2
13 -- 3
12 -- 4
11 -- 存在一个起始任务,为任务结束( 11+5 )时的值,即此时间必须工作到任务结束,中间没有多余空余时间 -- 0
10 -- 1
9 -- 2
8 -- 存在两个起始任务,取最大值Max( 2,3 ) -- 3
7 -- 4
6 -- 5
5 -- 6
4 -- 存在一个起始任务,结束时间 4+11 --1
3 -- 2
2 -- 3
1 -- 存在两个起始任务,取最大值Max( 2,4 ) -- 4
题意为从第一分钟开始干活,所以得到的4就是可以得到的最大空余时间。
状态转移方程, 没起始任务:dp[ind] = dp[ind+1] + 1,有起始任务:dp[ind] = Max(dp[ind+k1],dp[ind+k2]……)
#include<stdio.h>
#include<stdlib.h>
#define arraymax 10005
#define Max(a,b) (a>b?a:b)
#define write printf("%d\n",dp[1])
struct member
{
int p;
int k;
}mem[arraymax];
int dp[arraymax];
int cmp(const void* a,const void* b)
{
struct member* x=(struct member*)a;
struct member* y=(struct member*)b;
return (x->p<y->p);
}
int main(int argc,char* argv[])
{
int n,k;
scanf("%d%d",&n,&k);
for(int ind=1;ind<=k;ind++)
scanf("%d%d",&mem[ind].p,&mem[ind].k);
qsort(mem+1,k,sizeof(mem[0]),cmp);
for(int ind=n,jnd=1;ind>=1;ind--)
{
if(mem[jnd].p==ind)
{
while(mem[jnd].p==ind)
{
dp[ind]=Max(dp[ind],dp[ind+mem[jnd].k]);
jnd++;
}
}
else
dp[ind]=dp[ind+1]+1;
}
write;
return 0;
}