HNOI2004 打砖块

来源:互联网 发布:eve四种泰坦数据 编辑:程序博客网 时间:2024/06/03 00:28

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

原创粉丝点击