关于尼克的任务题解
焦祺 08-11-22
Time Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)
Problem Description
尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。
尼克的一个工作日为N分钟,从第一分钟开始到第N分钟结束。当尼克到达单位后他就开始干活。如果在同一时刻有多个任务需要完戍,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去完成,假如某些任务开始时刻尼克正在工作,则这些任务也由尼克的同事完成。如果某任务于第P分钟开始,持续时间为T分钟,则该任务将在第P+T-1分钟结束。
写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间。
Input
输入数据第一行含两个用空格隔开的整数N和K(1≤N≤10000,1≤K≤10000),N表示尼克的工作时间,单位为分钟,K表示任务总数。
接下来共有K行,每一行有两个用空格隔开的整数P和T,表示该任务从第P分钟开始,持续时间为T分钟,其中1≤P≤N,1≤P+T-1≤N。
Output
输出仅一行,包含一个整数,表示尼克可能获得的最大空暇时间。
Sample Input
15 6
1 2
1 6
4 11
8 5
8 1
11 5
Sample Output
4
初练DP不久,功底不是很强
加上黑白棋一题刚被一大牛BS了,无耐之下,好好学习DP
现在才愈加的感受到前人的一句话:
DP非一日之功!
其实DP的题目变化较多,没有个固定的模式,学习起来还是要有耐心的
看到别人用PASCAL写的程序,帮他注释之后了解了其解题大意:
用EXCEL模拟了一下,便写出程序AC了。
var n,m,i,j:longint;
f,t,p:array[0..10001]of integer;
begin
while not eof do 如果不为EOF时,循环
begin
read(n,m); 读取N,M
for i:=1 to m do read(p[i],t[i]); 读取START TIME 和 last TIME
f[n+1]:=0;j:=m; F[N+1] = 0; J = M;
for i:=n downto 1 do for(i=n;i>=1;i--)
begin {
f[i]:=0; f[i] = 0;
if p[j]<>i then f[i]:=f[i+1]+1 if(p[j] != i) f[i] = f[i+1] + 1;
else else
while p[j]=i do while(p[j] == i)
begin {
if f[i+t[j]]>f[i] then if(f[i+t[j] > f[i]])
f[i]:=f[i+t[j]]; f[i] = f[i+t[j]];
dec(j); j--
end; }
end; }
writeln(f[1]); 打印出F[1]
end;
end.
过程模拟:从后往前找! | |||||||||||||||||
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | # | # | # | # | # | # |
| |
| 1 | 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
| 1 | 1 | 1 | 1 | 1 | 1 |
|
|
|
|
|
|
|
|
|
| |
|
|
|
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
|
| |
|
|
|
|
|
|
|
| 1 | 1 | 1 | 1 | 1 |
|
|
|
| |
|
|
|
|
|
|
|
| 1 |
|
|
|
|
|
|
|
| |
|
|
|
|
|
|
|
|
|
|
| 1 | 1 | 1 | 1 | 1 |
| |
F | 0 | 4 | 3 | 2 | 1 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 4 | 3 | 2 | 1 | 0 |
//红色为开始时间,F为剩余时间,水绿标记空闲时间 | |||||||||||||||||
AC代码:
#include <iostream>
using namespace std;
int main()
{
int i,j,k,n,m;
//N和M(1≤N≤10000,1≤M≤10000),N表示尼克的工作时间,单位为分钟,M表示任务总数
int f[10001],last[10001],start[10001];
while (scanf("%d %d",&n,&m) != EOF)
{
for (i=1;i<=m;i++)
{
scanf("%d %d",&start[i],&last[i]); // 读取START TIME 和 last TIME
}
f[n+1] = 0; j = m; //j来标记开始值
for(i=n;i>=1;i--)
{
f[i] = 0;
if(start[j] != i) //如果不是在i时刻开始的
f[i] = f[i+1] + 1; //那么 f[i]就在上一个的基础上加1,找下一时刻
else //如果在i时刻开始的
{ //那么:
while (start[j] == i) //循环来遍历i时刻有多个开始任务
{ //判断选取哪一个
if(f[i+last[j]] > f[i]) //当前点 和 结束点比较
f[i] = f[i+last[j]]; //选空闲时间大的点哦!
j--; //找下一个同开始时间的点
}
}
}
printf("%d/n",f[1]);
}
return 0;
}