A Rectangular Barn (rectbarn)[USACO 6.1.2]

算法:DP

分析:绝对是经典问题!
      最大子矩阵问题,即一个矩形的某个点为坏点(这个点不能访问)。
      我们可以采用枚举每个点的方法,然后将这个点向三个方向扩展一下,直到碰到障碍点为止,由此又得到了一个小矩形。我们给它命名为极大矩形,那么我们要求的就是极大矩形里面最大的那一个,而这个也可以通过枚举求得。
      如果要寻找教程的话可以参考2003年的国家集训队论文《用极大化思想解决最优子矩阵问题》。
      然后借用一下离散化的思想,h[j]表示(i,j)最大能向下扩展的长度,同理l[j]表示向左扩展到哪里,r[j]表示向右扩展到哪里。
      那么最后h[j]*(r[j]-l[j]+1)就是这一个极大矩形的面积,不断更新这个最大值。
      因为如果从左往右算最终可能出现遗漏,所以还要从右往左算一下避免状态缺失。
      
思考:最大子矩阵问题非常经典,可以引伸出最大子矩阵和和最大子正方形等问题,但是大体思路基本上都是和最大子矩阵相似。 
{

ID:1011mashuo

PROG:rectbarn

LANG:PASCAL

}



program rectbarn;



const

 maxr=3000;

 maxc=3000;



var

 ans,n,m,p:longint;

 map:array [0..maxr,0..maxc] of boolean;

 l,r,h:array [0..maxr] of longint;

 

procedure init;

var

 i,x,y:longint;

begin

 ans:=-maxlongint;

 fillchar(map,sizeof(map),false);

 readln(n,m,p);

 for i:=1 to p do

  begin

   readln(x,y);

   map[x,y]:=true;

  end;

end;



function max(x,y:longint):longint;

begin

 if x>y then exit(x) else exit(y);

end;



procedure main;

var

 i,j,lmax,rmax:longint;

begin

 for i:=1 to m do

  begin

   l[i]:=1;{首先都设成最小值。}

   r[i]:=m;

   h[i]:=0;

  end;

 for i:=1 to n do

  begin

   lmax:=1;

   for j:=1 to m do

    begin

     if not map[i,j] then

      begin

       inc(h[j]);

       if l[j]<lmax then l[j]:=lmax;{这里如果出现冲突,那么一定不能超过这个冲突,因为行数没有变,所以冲突一直保留。}

      end

     else

      begin
       {如果是障碍点,再初始化一下。}

       h[j]:=0;

       l[j]:=1;

       r[j]:=m;

       lmax:=j+1;

      end;

    end;

   rmax:=m;

   for j:=m downto 1 do

    begin

     if not map[i,j] then

      begin

       if r[j]>rmax then r[j]:=rmax;{确定了右边界之后就可以得出极大矩形了。}

       ans:=max((r[j]-l[j]+1)*h[j],ans);

      end

     else rmax:=j-1;

    end;

  end;

end;



begin

 assign(input,'rectbarn.in'); reset(input);

 assign(output,'rectbarn.out'); rewrite(output);

 

 init;

 main;

 writeln(ans);

 

 close(input); close(output);

end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值