HNOI2004 打磚塊

描述 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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章