问题描述:
某人得到一块N*M个小格的矩形石材(可能是玉石),经专家分析,把这个矩形石材的每个小格都有一个价值(使用一个绝对值不大于10的整数来描述),现在将这块石材切割成两块矩形石材,注意,切割只能与该矩形边平行,也就是说不能把矩形的小格切碎,假设每块矩形石材的价值为该矩形中所有小格子价值之和。
问怎样切割,才能使得这两个矩形的价值乘积最大。如下图是一种比较好的切割方式。
输入格式:
输入文件BRICK.IN的第一行为2个正整数N和M,表示石材被划分为N*M个格子。接下来N行,每行有M个整数,代表这个格子的价值。
输出格式:
输出文件BRICK.OUT只有一行,包含一个整数,为两个矩形的价值的最大乘积。
输入样例 |
输出样例 |
3 4 -1 -1 -1 -1 0 0 0 0 -1 -1 -1 -1 |
16 |
数据范围
对于30%的数据,满足N,M≤5。
对于100%的数据,满足N,M≤100。每个小格的伤害值的绝对值不超过10。
一切数据及中间变量不超过longint范围。
==================================
============================================
我开始的算法O(n^4)【90分】
我是先枚举切线的...就比满分算法大约多了一维
------------------------------------
【我的算法.】
var
n,m:longint;
map:array[1..100,1..100]of longint;
sum:array[1..100,0..100]of longint;
f1,f2:array[0..100]of longint;
procedure init;
begin
assign(input,'brick.in');
assign(output,'brick.out');
reset(input); rewrite(output);
end;
procedure terminate;
begin
close(input); close(output);
halt;
end;
procedure main;
var
i,j:longint;
max,min:longint;
s_min1,s_max1,s_min2,s_max2:longint;
ans:longint;
n1,n2:longint;
now:longint;
begin
readln(n,m);
fillchar(sum,sizeof(sum),0);
for i:=1 to n do
for j:=1 to m do
begin
read(map[i,j]);
sum[i,j]:=sum[i-1,j]+map[i,j];
end;
ans:=-maxlongint;
for i:=1 to n-1 do
begin
s_min1:=maxlongint;
s_min2:=maxlongint;
s_max1:=-maxlongint;
s_max2:=-maxlongint;
for n1:=1 to i do
for n2:=n1 to i do
begin
//fillchar(f1,sizeof(f1),0); //max
//fillchar(f2,sizeof(f2),0); //min
f1[0]:=0;
f2[0]:=0;
for j:=1 to m do
begin
now:=sum[n2,j]-sum[n1-1,j];
if nowf1[j-1]+now then f1[j]:=now
else f1[j]:=f1[j-1]+now;
if f1[j]>s_max1 then s_max1:=f1[j];
if f2[j]f1[j-1]+now then f1[j]:=now
else f1[j]:=f1[j-1]+now;
if f1[j]>s_max2 then s_max2:=f1[j];
if f2[j]ans then ans:=s_min1*s_min2;
if s_max1*s_max2>ans then ans:=s_max1*s_max2;
end;
for i:=1 to m-1 do
begin
s_min1:=maxlongint;
s_min2:=maxlongint;
s_max1:=-maxlongint;
s_max2:=-maxlongint;
for n1:=1 to n do
for n2:=n1 to n do
begin
//fillchar(f1,sizeof(f1),0); //max
//fillchar(f2,sizeof(f2),0); //min
f1[0]:=0;
f2[0]:=0;
for j:=1 to i do
begin
now:=sum[n2,j]-sum[n1-1,j];
if nowf1[j-1]+now then f1[j]:=now
else f1[j]:=f1[j-1]+now;
if f1[j]>s_max1 then s_max1:=f1[j];
if f2[j]f1[j-1]+now then f1[j]:=now
else f1[j]:=f1[j-1]+now;
if f1[j]>s_max2 then s_max2:=f1[j];
if f2[j]ans then ans:=s_min1*s_min2;
if s_max1*s_max2>ans then ans:=s_max1*s_max2;
end;
writeln(ans);
end;
begin
init;
main;
terminate;
end.
-------------------------------------
满分算法约等于O(n^3)
不用枚举切线...
-----------------------------------------------
【满分算法】
var
n,m:longint;
map:array[1..100,1..100]of longint;
sum:array[0..100,0..100]of longint;
j1,j2:array[1..100,1..100]of longint;
f1,f2:array[0..100]of longint;
procedure init;
begin
assign(input,'brick.in');
assign(output,'brick.out');
reset(input); rewrite(output);
end;
procedure terminate;
begin
close(input); close(output);
halt;
end;
procedure main;
var
i,j:longint;
max,min:longint;
s_min1,s_max1:longint;
ans:longint;
n1,n2,m1,m2:longint;
now:longint;
begin
readln(n,m);
fillchar(sum,sizeof(sum),0);
for i:=1 to n do
for j:=1 to m do
begin
read(map[i,j]);
sum[i,j]:=sum[i-1,j]+map[i,j];
end;
ans:=-maxlongint;
//--------------------------------------------------------------->初始化...
fillchar(j1,sizeof(j1),0);
fillchar(j2,sizeof(j2),0);
for n1:=1 to n do
for n2:=n1 to n do
begin
f1[0]:=0;
f2[0]:=0;
s_min1:=maxlongint;
s_max1:=-maxlongint;
for j:=1 to m do
begin
now:=sum[n2,j]-sum[n1-1,j];
if nowf1[j-1]+now then f1[j]:=now
else f1[j]:=f1[j-1]+now;
if f1[j]>s_max1 then s_max1:=f1[j];
if f2[j]ans then ans:=j1[n1,n2]*j1[m1,m2];
if j2[n1,n2]*j2[m1,m2]>ans then ans:=j2[n1,n2]*j2[m1,m2];
end;
//---------------------------------------------------------->以n为边界切的情况..
fillchar(sum,sizeof(sum),0);
for i:=1 to n do
for j:=1 to m do
begin
sum[i,j]:=sum[i,j-1]+map[i,j];
end;
s_min1:=maxlongint;
s_max1:=-maxlongint;
for m1:=1 to m do
for m2:=m1 to m do
begin
f1[0]:=0;
f2[0]:=0;
s_min1:=maxlongint;
s_max1:=-maxlongint;
for j:=1 to n do
begin
now:=sum[j,m2]-sum[j,m1-1];
if nowf1[j-1]+now then f1[j]:=now
else f1[j]:=f1[j-1]+now;
if f1[j]>s_max1 then s_max1:=f1[j];
if f2[j]ans then ans:=j1[n1,n2]*j1[m1,m2];
if j2[n1,n2]*j2[m1,m2]>ans then ans:=j2[n1,n2]*j2[m1,m2];
end;
//--------------------------------------------------------->以m为边界的情况..
writeln(ans);
end;
begin
init;
main;
terminate;
end.