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]);
}
}