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