【动态规划】石材切割

来源:互联网 发布:微软养活中国程序员 编辑:程序博客网 时间:2024/04/28 14:33

PROBLEM 2.石材切割

 

问题描述:

某人得到一块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范围。



划分矩形,无非就两种,切成上下两部分,切成左右两部分。

我们枚举分割线,答案要么是两部分里最小的矩形的乘积,要么是两部分里最大的矩形的乘积。


然后就转化为了求最大子矩形的问题,这道题用压缩的方法就能过。。。但是我傻逼了。

在求最大子序和的时候,s+a[k]<0写成了a[k]小于零。。这其实就是加速度小于零,但是速度不一定小于零的道理。。。


#include <cstdio>#include <algorithm>using std::min;using std::max;long a[120];long map[120][120];long sum[120][120];long f1[120][120];long f2[120][120];long g1[120];long g2[120];long h1[120];long h2[120];long ans = -0x3f3f3f3f;long getint(){long rs=0;bool sgn=1;char tmp;do tmp=getchar();while (!isdigit(tmp)&&tmp-'-');if (tmp=='-'){tmp=getchar();sgn=0;}do rs=(rs<<3)+(rs<<1)+tmp-'0';while (isdigit(tmp=getchar()));return sgn?rs:-rs;}int main(){freopen("brick.in","r",stdin);freopen("brick.out","w",stdout);long n = getint();long m = getint();for (long i=1;i<n+1;i++)for (long j=1;j<m+1;j++)map[i][j] = getint();//---------------------------------------------Horizonfor (long i=1;i<n+1;i++)for (long j=1;j<m+1;j++)sum[i][j] = sum[i-1][j] + map[i][j];for (long i=1;i<n+1;i++){for (long j=i;j<n+1;j++){for (long k=1;k<m+1;k++)a[k] = sum[j][k]-sum[i-1][k];long s = 0;long _ans = a[1];for (long k=1;k<m+1;k++){if (s+a[k] < 0)s = 0;else{s = s + a[k];if (_ans < s)_ans = s;}}f1[i][j] = _ans;s = 0;_ans = a[1];for (long k=1;k<m+1;k++){if (s+a[k] > 0)s = 0;else{s = s + a[k];if (_ans > s)_ans = s;}}f2[i][j] = _ans;}}memset(g1,~0x3f,sizeof g1);memset(h1,~0x3f,sizeof h1);memset(g2,0x3f,sizeof g2);memset(h2,0x3f,sizeof h2);for (long i=1;i<n+1;i++){for (long j=i;j<n+1;j++){g1[j] = max(g1[j],f1[i][j]);g2[j] = min(g2[j],f2[i][j]);h1[i] = max(h1[i],f1[i][j]);h2[i] = min(h2[i],f2[i][j]);}}for (long i=2;i<n+1;i++){g1[i] = max(g1[i],g1[i-1]);g2[i] = min(g2[i],g2[i-1]);}for (long i=n-1;i>0;i--){h1[i] = max(h1[i],h1[i+1]);h2[i] = min(h2[i],h2[i+1]);}for (long i=1;i<n;i++){if (g1[i]>-0x3f3f3f3f && h1[i+1]>-0x3f3f3f3f)ans = max(ans,g1[i]*h1[i+1]);if (g2[i]<0x3f3f3f3f && h2[i+1]<0x3f3f3f3f)ans = max(ans,g2[i]*h2[i+1]);}//---------------------------------------------Verticalfor (long j=1;j<m+1;j++)for (long i=1;i<n+1;i++)sum[i][j] = sum[i][j-1] + map[i][j];memset(f1,0,sizeof f1);memset(f2,0,sizeof f2);for (long i=1;i<m+1;i++){for (long j=i;j<m+1;j++){for (long k=1;k<n+1;k++)a[k] = sum[k][j]-sum[k][i-1];long s = 0;long _ans = a[1];for (long k=1;k<n+1;k++){if (s+a[k] < 0)s = 0;else{s = s + a[k];if (_ans < s)_ans = s;}}f1[i][j] = _ans;s = 0;_ans = a[1];for (long k=1;k<n+1;k++){if (s+a[k] > 0)s = 0;else{s = s + a[k];if (_ans > s)_ans = s;}}f2[i][j] = _ans;}}memset(g1,~0x3f,sizeof g1);memset(h1,~0x3f,sizeof h1);memset(g2,0x3f,sizeof g2);memset(h2,0x3f,sizeof h2);for (long i=1;i<m+1;i++){for (long j=i;j<m+1;j++){g1[j] = max(g1[j],f1[i][j]);g2[j] = min(g2[j],f2[i][j]);h1[i] = max(h1[i],f1[i][j]);h2[i] = min(h2[i],f2[i][j]);}}for (long i=2;i<m+1;i++){g1[i] = max(g1[i],g1[i-1]);g2[i] = min(g2[i],g2[i-1]);}for (long i=m-1;i>0;i--){h1[i] = max(h1[i],h1[i+1]);h2[i] = min(h2[i],h2[i+1]);}for (long i=1;i<m;i++){if (g1[i]>-0x3f3f3f3f && h1[i+1]>-0x3f3f3f3f)ans = max(ans,g1[i]*h1[i+1]);if (g2[i]<0x3f3f3f3f && h2[i+1]<0x3f3f3f3f)ans = max(ans,g2[i]*h2[i+1]);}//---------------------------------------------printf("%ld",ans);return 0;}


原创粉丝点击