敲磚塊(codevs 1257)題解

【問題描述】

在一個凹槽中放置了 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 塊磚,求得分最多能有多少。

【樣例輸入】

   4 5
   2 2 3 4
   8 2 7
   2 3
   49

【樣例輸出】

    19

【解題思路】

 本題爲湖南省選2004day2的題,初看題目感覺並不好做,然而看了樣例之後,我們可以發現一些很神奇的事情……樣例是把倒三角變成一個倒直角三角,於是,我們可以清晰地發現,若要打第i列的第j個磚塊,那麼必須至少打掉第i+1列的前j-1個磚塊以及第i列的前j-1個磚塊,因爲第i列的前j-1個磚塊我們可以循環得出,因此設現在需要打第i列的第j個磚塊,總共打了k個磚塊,f[i,j,k]就表示這種狀態下的最大值。因此我們可以發現,f[i,j,k]只與f[i+1,l,k-j]有關,l爲>=j-1的數,用最大的f[i+1,l,k-j]加上這一列上從第1個到第j個得分即可,那麼DP方程就出來了,然後再看看題目數據範圍,可以做DP,時間複雜度爲O(n^3*m)需要注意幾點:由於i與i+1有關,因此我們把i倒過來循環會好一些,其次j要從0開始循環,例如樣例,當你要打第一列第二個時,你可以選擇打第一列第一個,第二列第一個,和第四列第一個,這樣第三列就是0了。26行代碼,應該是省選題目中代碼最短的了……

【代碼實現】

 1 var a:array[0..55,0..55] of longint;  
 2     i,j,n,m,k,l,max:longint;  
 3     f:array[-1..55,-1..55,-1..1300] of longint;  
 4 begin  
 5  readln(n,m);  
 6  for i:=1 to n do  
 7   for j:=1 to n-i+1 do  
 8    read(a[i,j]);  
 9  for i:=n downto 1 do  
10   for j:=0 to n-i+1 do  
11    for k:=2*j-1 to m do  
12     begin  
13      max:=0;  
14      for l:=j-1 to n-i+1 do  
15       if f[i+1,l,k-j]>max then  
16        max:=f[i+1,l,k-j];  
17      f[i,j,k]:=max;  
18      for l:=1 to j do  
19       inc(f[i,j,k],a[l,i]);  
20     end;  
21  for i:=1 to n do  
22   for j:=0 to n-i+1 do  
23    if f[i,j,m]>max then  
24     max:=f[i,j,m];  
25  writeln(max);  
26 end.  

 

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