hdu 3905 Sleeping——DP

大意:ZZZ 喜欢睡觉,一堂课有N分钟,他至少要睡M分钟,他一旦听课就要连续地听L分钟。每分钟都有一个他可以拿到的分数。求他可以得到的最大分数。

dp[i][j]在第i分钟,已经休息了j分钟的时候能得到的能得到的最大分数。

sum[i]记录i以及以前的分数和。防止重复计算。

状态转移方程

dp[i][j]=max(dp[i-1][j-1],max(dp[i-k][j]+sum[i]-sum[i-k]))其中k>=l,k<=i-j

                 表示这分钟睡觉了         表示这分钟在学习

如果我们在每次循环的时候都把max(dp[i-k][j]+sum[i]-sum[i-k])重新算一遍,这样会超时。res数组用来记录最大值,避免重复计算。

上代码:

2011-08-04 10:57:03 Accepted 3905 312MS 8156K 1041 B G++ LadyTutu
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<algorithm>
#include
<cmath>

int dp[1010][1010];
int score[1010];
int sum[1010];
int res[1010][1010];

int Min(int a,int b)
{
return a>b?b:a;
}

int Max(int a,int b)
{
return a>b?a:b;
}

int main(void)
{
int n,m,l;
while(scanf("%d %d %d",&n,&m,&l)==3)
{
memset(dp,
0,sizeof(dp));
memset(score,
0,sizeof(score));
memset(sum,
0,sizeof(sum));
memset(res,
0,sizeof(res));
int i;
for(i=1;i<=n;i++)
{
scanf(
"%d",&score[i]);
sum[i]
+=sum[i-1]+score[i];
if(i>=l)
dp[i][
0]=sum[i];
for(int j=0;j<=m;j++)
if(n-i+j<m)
dp[i][j]
=-1;
}
int j;
for(i=1;i<=n;i++)
for(j=1;j<=Min(m,i);j++)
{
/* int max=0;//这个就是会超时的写法……
for(int k=l;k+j<=i;k++)
{
if(dp[i-k][j]+sum[i]-sum[i-k]>max)
max=dp[i-k][j]+sum[i]-sum[i-k];
}
*/
if(i>=l+j)
res[i][j]
=Max(res[i-1][j]+score[i],dp[i-l][j]+sum[i]-sum[i-l]);
dp[i][j]
=Max(dp[i-1][j-1],res[i][j]);
}
printf(
"%d\n",dp[n][m]);
}
}

  

你可能感兴趣的:(sleep)