本题是求一个没有损坏区域的最大子矩阵。显然要用DP来做。 当然,由于本题是矩形,所以big barn的方法就无法用到这里了。 现在我们换一种思路。 如果找到一个点,把这个点向上、左、右三个方向扩展,那么统计扩展出来的尽可能大的矩形就行了。看起来这种算法的时间复杂度很高,这也正是DP的用处——解决大量重复子问题。否则这样的算法就成了枚举了。
设h[i,j]为点(i,j)向上方扩展的最大高度,l[i,j]为(i,h[i,j])这条线段向左边扩展的最长距离,r[i,j]为(i,h[i,j])向右边扩展的最长距离。 转移方程:
其中,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.