USACO 6.1.2 A Rectangular Barn dp

本题是求一个没有损坏区域的最大子矩阵。显然要用DP来做。 当然,由于本题是矩形,所以big barn的方法就无法用到这里了。 现在我们换一种思路。 如果找到一个点,把这个点向上、左、右三个方向扩展,那么统计扩展出来的尽可能大的矩形就行了。看起来这种算法的时间复杂度很高,这也正是DP的用处——解决大量重复子问题。否则这样的算法就成了枚举了。

DP

设h[i,j]为点(i,j)向上方扩展的最大高度,l[i,j]为(i,h[i,j])这条线段向左边扩展的最长距离,r[i,j]为(i,h[i,j])向右边扩展的最长距离。 转移方程: USACO 6.1.2 A Rectangular Barn dp_第1张图片

其中,tl表示点(i,j)向左扩展的最大距离,tr表示点(i,j)向右扩展的最大距离。

注意USACO的内存限制比较严格,需要用滚动数组.

代码:

{
ID: ymwbegi1
PROG: rectbarn
LANG: PASCAL
}

var
  tl,tr,n,m,p,i,j,ans,x,y:longint;
  h,l,r:array[0..1,0..3001] of longint;
  a:array[1..3000,1..3000] of 0..1;

function min(x,y:longint):longint;
begin
  if x<y then exit(x)
         else exit(y);
end;

begin
  assign(input,'rectbarn.in');
  assign(output,'rectbarn.out');
  reset(input);
  rewrite(output);
  readln(n,m,p);
  for i:=1 to p do
  begin
    readln(x,y);
    a[x,y]:=1;
  end;
  fillchar(l,sizeof(l),$7f);
  fillchar(r,sizeof(r),$7f);
  x:=0;
  for i:=n downto 1 do
  begin
    tl:=0;
    tr:=0;
    for j:=1 to m do
      if a[i,j]=0
        then begin
               inc(tl);
               l[x,j]:=min(l[1-x,j],tl);
             end
        else begin
               tl:=0;
               l[x,j]:=maxlongint;
             end;
    for j:=m downto 1 do
      if a[i,j]=0
        then begin
               inc(tr);
               r[x,j]:=min(r[1-x,j],tr);
             end
        else begin
               tr:=0;
               r[x,j]:=maxlongint;
             end;
    for j:=1 to m do
      if a[i,j]=0
        then begin
               h[x,j]:=h[1-x,j]+1;
               if h[x,j]*(l[x,j]+r[x,j]-1)>ans then
                 ans:=h[x,j]*(l[x,j]+r[x,j]-1);
             end
        else h[x,j]:=0;
    x:=1-x;
  end;
  writeln(ans);
  close(input);
  close(output);
end.


你可能感兴趣的:(USACO 6.1.2 A Rectangular Barn dp)