【石材切割】解题报告

PROBLEM2.石材切割


问题描述:

某人得到一块N*M个小格的矩形石材(可能是玉石),经专家分析,把这个矩形石材的每个小格都有一个价值(使用一个绝对值不大于10的整数来描述),现在将这块石材切割成两块矩形石材,注意,切割只能与该矩形边平行,也就是说不能把矩形的小格切碎,假设每块矩形石材的价值为该矩形中所有小格子价值之和。

问怎样切割,才能使得这两个矩形的价值乘积最大。如下图是一种比较好的切割方式。

输入格式:

输入文件BRICK.IN的第一行为2个正整数NM,表示石材被划分为N*M个格子。接下来N行,每行有M个整数,代表这个格子的价值。


输出格式:

输出文件BRICK.OUT只有一行,包含一个整数,为两个矩形的价值的最大乘积


输入样例

输出样例

34

-1-1 -1 -1

00 0 0

-1 -1-1 -1

16


数据范围

对于30%的数据,满足N,M≤5

对于100%的数据,满足N,M≤100。每个小格的伤害值的绝对值不超过10

一切数据及中间变量不超过longint范围。



此题调得甚为蛋疼。。

最开始的时候没有读懂题,以为就切一刀就行了,然后就分成了两个矩形,原来切的数量任意。

当时是WA50,人品也还是不错了。
这是一道最大子矩形和+枚举的题。说的是O(n^3),可是我怎么看怎么是O(n^4)。


先讲最大子矩形和。就是压缩的方法,枚举上下界或者左右界,对每一个上下界或左右界求一个最大子区间和。
这里要用到二维前缀和。(这里一开始一直没弄清楚,应该是第j列的前i行、第i行的前j列,而不是前i行前j列)

预处理出来之后,就可以用O(n^4)来枚举两个上下界,或两个左右界,求出最优解。

本题要注意的就是有可能最优解是两个最小的负数相乘得来。所以总共进行四次DP。出解

AC程序

//#include 
//using std::cout;
//using std::cin;
#include 
const long oo = 0x7fff0000;

long n;long m;
long num[110][110];
long sum[110][110];
long sum2[110][110];
long f[110][110];
long ans = -oo;

int main()
{
	freopen("brick.in","r",stdin);
	freopen("brick.out","w",stdout);
	
	scanf("%ld%ld",&n,&m);
	for (long i=1;i0) max+=x;
				else max = x;
				
				if (f[i][j] < max)
					f[i][j] = max;
			}
		}
	}
	
	for (long i=1;i?= f[i][j]*f[k][l];
				}
			}
		}
	}
	
	for (long i=1;i0) max+=x;
				else max = x;
				
				if (f[i][j] < max)
					f[i][j] = max;
			}
		}
	}

	for (long i=1;i?= f[i][j]*f[k][l];
				}
			}
		}
	}
	long min = oo;
	for (long i=1;i min)
					f[i][j] = min;
			}
		}
	}
	for (long i=1;i?= f[i][j]*f[k][l];
				}
			}
		}
	}
	
	for (long i=1;i min)
					f[i][j] = min;
			}
		}
	}
	
	for (long i=1;i?= f[i][j]*f[k][l];
				}
			}
		}
	}
	
	printf("%ld",ans);
	return 0;
}




50分程序:
//#include 
//using std::cout;
//using std::cin;
#include 
const long oo = 0x7fff0000;

long n;long m;
long s1[110];
long s2[110];
long ss = 0;
long num[110][110];

int main()
{
	freopen("brick.in","r",stdin);
	freopen("brick.out","w",stdout);
	
	scanf("%ld%ld",&n,&m);
	for (long i=1;i




你可能感兴趣的:(NOIP)