描述 Description
在一個凹槽中放置了n層磚塊、最上面的一層有n 塊磚,從上到下每層依次減少一塊磚。每塊磚都有一個分值,敲掉這塊磚就能得到相應的分值,如下圖所示。
14 15 4 3 23
33 33 76 2
2 13 11
22 23
31
如果你想敲掉第i層的第j塊磚的話,若i=1,你可以直接敲掉它;若i>1,則你必須先敲掉第i-1層的第j和第j+1塊磚。
你現在可以敲掉最多m塊磚,求得分最多能有多少。
輸入格式 Input Format
輸入文件的第一行爲兩個正整數n和m;接下來n行,描述這n層磚塊上的分值a[I][j],滿足0≤a[j] ≤100。
輸出格式 Output Format
輸出文件僅一行爲一個正整數,表示被敲掉磚塊的最大價值總和。
描述就是這些了,其實恍然大悟之後覺得還蠻簡單的,可是之前還是沒有想到算法。
關鍵是每一行的選擇沒有連續性,也就是沒有規律,所以很麻煩。
於是我們要創造規律,所以改變取數規則:將圖旋轉
14
15 33
4 33 2
3 76 13 22
23 2 11 23 31
這樣每一行必須從左往右去連續的,並且第i行取j個,第i-1行至少要取j-1個。
所以dp方程就好 寫了:f[i,j,k]:=max{f[i-1,p,j-k]+sum[1,j]}
獻上代碼:
program brick_hnoi;
var
sum,a,b:array[0..50,0..50]of longint;
f:array[0..50,0..500,0..500]of longint;
i,j,k,m,n,ans,p:longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
begin
read(n,m);
for i:=1 to n do
for j:=i to n do read(a[j,i]);
fillchar(sum,sizeof(sum),0);
for i:=1 to n do
for j:=1 to i do sum[i,j]:=sum[i,j-1]+a[i,j];
fillchar(f,sizeof(f),255);
for i:=0 to n do f[i,0,0]:=0;
for i:=1 to n do f[i,1,1]:=a[i,1];
for i:=1 to n do
for k:=0 to i do
for j:=0 to m do
if k<=j then
for p:=k-1 to i do
if f[i-1,j-k,p]<>-1 then
begin
f[i,j,k]:=max(f[i-1,j-k,p]+sum[i,k],f[i,j,k]);
if (j=m)and(f[i,j,k]>ans) then ans:=f[i,j,k];
end;
writeln(ans);
end.
(其實不是原創,好邪惡。。。)
End。