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

来源:互联网 发布:淘宝娱乐 编辑:程序博客网 时间:2024/04/28 01:55
 石材切割 

问题描述:

某人得到一块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 now<f2[j-1]+now then f2[j]:=now                                   else f2[j]:=f2[j-1]+now;                if now>f1[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]<s_min1 then s_min1:=f2[j];              end;          end;                for n1:=i+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 m do              begin                now:=sum[n2,j]-sum[n1-1,j];                if now<f2[j-1]+now then f2[j]:=now                                   else f2[j]:=f2[j-1]+now;                if now>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]<s_min2 then s_min2:=f2[j];              end;          end;      if s_min1*s_min2>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 now<f2[j-1]+now then f2[j]:=now                                   else f2[j]:=f2[j-1]+now;                if now>f1[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]<s_min1 then s_min1:=f2[j];              end;          end;      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[i]:=0;0            f2[i]:=0;            for j:=i+1 to m do              begin                now:=sum[n2,j]-sum[n1-1,j];                if now<f2[j-1]+now then f2[j]:=now                                   else f2[j]:=f2[j-1]+now;                if now>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]<s_min2 then s_min2:=f2[j];              end;          end;      if s_min1*s_min2>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 now<f2[j-1]+now then f2[j]:=now                               else f2[j]:=f2[j-1]+now;            if now>f1[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]<s_min1 then s_min1:=f2[j];          end;        j1[n1,n2]:=s_max1;        j2[n1,n2]:=s_min1;      end;  //-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0  for n1:=1 to n do    for n2:=n1 to n do      for m1:=n2+1 to n do        for m2:=m1 to n do          begin            if j1[n1,n2]*j1[m1,m2]>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 now<f2[j-1]+now then f2[j]:=now                               else f2[j]:=f2[j-1]+now;            if now>f1[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]<s_min1 then s_min1:=f2[j];          end;        j1[m1,m2]:=s_max1;        j2[m1,m2]:=s_min1;      end;  //-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0  for n1:=1 to m do  for n2:=n1 to m do    for m1:=n2+1 to m do      for m2:=m1 to m do        begin          if j1[n1,n2]*j1[m1,m2]>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.   


 

原创粉丝点击