这是一道很明显的动态规划
动态规划方程如下: j表示前j分钟 i表示休息了i分钟 l 表示需要连续学习l分钟
以前 F[j][i] = f[j - 1][i-1] ;//如果当前不选择,那么当前的最大价值就是前j-1分钟选择i-1分钟休息的最大价值
= f[j-l][i]+sum(j-l,j)//如果当前选择的,那么的最大价值就等于前j-l分钟,休息i分钟的最大价值最大价值,加上学习了(j-l,j)这l分钟的价值
// 但是,他可能不止连续学习l分钟,可能会大学l分钟啊。。所以选择的方程因该改为学习了k分钟,而k>=l
=f[j-k][i]+sum(j-k,j) k=l,l+1,。j - i 中的最大价值
很明显这是一个o(n^3)的方程,会超时的 只有o(n^2)才不会超时啊~
这该怎么把方程将为二维呢。。我们另外设置一个数组sel[j][i]来表示当前第j分钟一定会被选择 a[j]表示当前的分钟的得分
那么对于sel[j][i]=sel[j-k][i]+sum(j-k,j) k=l,l+1,。j - i 中的最大价值
那么sel[j+1][i]=sel[j-k+1][i]+sum(j-k+1,j)k=l,l+1,...j+1-i 两者之间似乎有点相似之处。。
当k=m时,sel[j][i] = sel[j - l][i] + sum(j-l,j)
sel[j+1][i] = sel[j+1-l][i]+sum(j+1-l,j+1) //不能被前j分钟选择i分钟休息包括
当k=m+1时sel[j][i]=sel[j-l-1][i] + sum(j-l-1,j);
sel[j+1][i]=sel[j+1-l-1] +sum(j+1-l-1,j+1)
=sel[j-l]+sum(j-l,j+1)
=sel[j-l] + sum(j-l,j)+a[j];
当k = m+2时 sel[j][i] = sel[j-l-2][i]+sum(j-l-2,j)
sel[j+1] = sel[j+1-l-2] +sum(j+1-l-2,j+1)
= sel[j-l-1]+sum(j-l-1,j+1)
= sel[j-l-1][i] + sum(j-l-1,j) +a[j]
观察画横线的地方是不是一样的。而所有的画横线都在sel[j][i]中就计算过一次了,
规律很明显了
sel[j+1][i] = max(sel[j+1-l][i]+sum(j+1-l,j+1),sel[j][i] + a[j]);
即当前点分钟被选择,有两种情况,一种是就选择l分钟
另外一种选择大于l分钟, 之中的最大
/*************************************************************************
> File Name: hdu3905.cpp
> Author: zwy
> Mail: zwy_qz@hotmail.com
> Created Time: 2012年11月25日 星期日 12时35分26秒
************************************************************************/
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int f[1009][1009];
int sel[1009][1009];
int a[1009];
int total[1009];
int n,m;
int _max(int a,int b)
{
if(a > b) return a;
return b;
}
void print(int f[][1009])
{
int i,j;
putchar('\n');
for(j = 0 ; j <= m ;j++)
{
for(i = 0 ; i < n ; i++)
printf("%5d ",f[i][j]);
putchar('\n');
}
}
int main()
{
int l;
int i,j;
int temp;
//freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&m,&l)!=EOF)
{
memset(f,0,sizeof(f));
memset(total,0,sizeof(total));
memset(sel,0,sizeof(sel));
for(i = 0 ; i < n ; i ++)
{
scanf("%d",&a[i]);
if(i == 0 )
total[i] = a[i];
else
total[i] = total[i-1] + a[i]; //前i分钟的和
f[i][0] = total[i];
sel[i][0]=total[i];
// printf("%d ",total[i]);
}
// printf("\n");
for(i = 1 ; i <= m ; i++)
{
for(j = l + i - 1 ; j < n ; j++)
{
int a1 = sel[j-1][i] + a[j]; //选择了大于l分钟进行学习
int a2 = f[j-1][i-1];
int a3 = f[j - l][i] + total[j] - total[j-l];//选择了了l分钟
sel[j][i] =_max(a1,a3);//当前选择的最大值等于两者之中的最大
f[j][i] = _max(a2,sel[j][i]);
// printf("%d ",j);
}
// printf("\n");
}
// print(f);
// print(sel);
int mymax = 0;
for(j = 0 ; j < n ; j++)
mymax=_max(mymax,f[j][m]);
printf("%d\n",mymax);
}
fclose(stdin);
return 0;
}