本题是一个显然的动态规划题目。设计状态时,用f[i,j,1]表示第i段时间为止,已睡去j个时间段,且第i段时间睡觉获得的最大效用。反之,f[i,j,0]表示上述状态下[i]第i段时间不睡觉能获得的最大效用值。
状态转移方程如下:
f[i,j,0]:=Max{f[i-1,j,0],f[i-1,j,1]}
f[i,j,1]:=Max{f[i-1,j-1,0],f[i-1,j-1,1]+u[i]}
具体就不用多解释了,这题的关键不在方程上,而在于的是环形Dp的处理。
上述方程从i=1开始顺推,推出的只能是第一段时间开始睡或者第一段时间没有睡的最大效用值,换句话说,就是无论如何没有把u[1]加入这个最大值中,但是题目要求有可能让我们把u[1]加入进去,所以只需考虑一下u[i]必被加入的情况。处理的方法就是,之前的初态为f[1,1,1]:=0;和f[1,0,0]:=0;其余f值均为-maxlongint(即将第一秒睡不睡的值都记为0),那么现在,我们只需把初态记为f[1,1,1]:=0;其余值均记为-maxlongint,然后再将f[n,b,1]+u[1]与原来更新出来的的ans值作比较即可。
注意:本题如果按照上述方程进行会占用较大内存,造成空间浪费,所以需要滚动数组优化。
CODE
Program POJ2228;
Const
maxn=3830;
Var
i,j,m,n,ans,k :Longint;
f,g :Array[0..1,0..maxn,0..1]of Longint;
v :Array[1..maxn]of Longint;
Function Max(i,j:Int64):Int64;
begin
if i>j then exit(i);exit(j);
end;
BEGIN
readln(n,m);
for i:=1 to n do readln(v[i]);
for i:=0 to m do
for j:=0 to 1 do
begin
f[1,i,j]:=-maxlongint;
g[1,i,j]:=-maxlongint;
end;
f[1,0,0]:=0;f[1,1,1]:=0;g[1,1,1]:=0;
k:=0;
for i:=2 to n do
begin
for j:=0 to m do
begin
f[k,j,0]:=Max(f[1-k,j,0],f[1-k,j,1]);
g[k,j,0]:=Max(g[1-k,j,0],g[1-k,j,1]);
if j>0 then
begin
f[k,j,1]:=Max(f[1-k,j-1,1]+v[i],f[1-k,j-1,0]);
g[k,j,1]:=Max(g[1-k,j-1,1]+v[i],g[1-k,j-1,0]);
end else
begin
f[k,j,1]:=-maxlongint;
g[k,j,1]:=-maxlongint;
end;
end;
k:=1-k;
end;
ans:=Max(f[1-k,m,0],Max(f[1-k,m,1],g[1-k,m,1]+v[1]));
writeln(ans);
END.