【DP~最大子矩阵】石材切割

 石材切割 

问题描述:

某人得到一块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.   


 

你可能感兴趣的:(NOIP2011黎明前夕的黑暗,动态规划,n2,output,input,算法)