poj1050-求二维数组子数组和的最大值

来源:互联网 发布:淘宝电脑改差评步骤 编辑:程序博客网 时间:2024/05/16 07:01

题意:给定一个二维数组,值有正有负,矩阵的规模不超过100*100,矩阵元素在-127到127之间,求该二维数组的一个子数组,使得该数组的元素之和在所有的子数组中是最大的。

解法一:

对整个矩阵进行枚举,采用四重循环,计算每个子矩阵的元素之和,在计算所有的子矩阵之和是有很多重复的计算,可以考虑用“空间换时间”的方法,先计算出以(1,1)为左上点,(i,j)为右下点所表示的矩阵元素之和为partSum[i,j].则以(x,y)为左上点(i,j)为右下点的矩阵元素之和为partSum[i,j] - partSum[i,y-1] - partSum[x-1,j] + parSum[x-1,y-1]

整个时间复杂度为O(m*n)+O(m*m*n*n) =  O(m*m*n*n);

解法二:

将二维转化为一维处理,解法一中使用了4重循环,第1,2重是对行的枚举,第3,4重是对列的枚举,这里将1,2重对行的枚举保留,当上下行(i表示上行,j表示下行)确定时,对列的选择可以看作是求一维数组子数组的最大和,只不过该一维数组中每个元素是由某列中第i到j行元素之和组成的,求一维数组子数组和的最大值可以参考我前一篇博客。

整个时间复杂度为O(m*n*min(m,n))

#include <stdio.h>int A[110][110];int partSum[110][110];/*方法一:使用四重循环枚举一个个的比较*//*求得从左上角到(i,j)所表示的矩阵的各元素的和*/void CalculatePartSum(int m, int n){int i, j;/*初始化处理*/for (i = 0; i <= n; i++){partSum[0][i] = 0;}for (i = 0; i <= m; ++i){partSum[i][0] = 0;}/*求值*/for (i = 1; i <= m; ++i){for (j = 1; j <= n; ++j){partSum[i][j] = partSum[i - 1][j] + partSum[i][j - 1] - partSum[i - 1][j - 1] + A[i][j];}}}int MaxSumOne(int m, int n){int maximum = -200;int i, j;int x, y;int sum;CalculatePartSum(m, n);/*求最大值,需要4重循环*/for (i = 1; i <= m; ++i){for (j = i; j <= m; ++j){for (x = 1; x <= n; x++){for (y = x; y <= n; y++){sum = partSum[j][y] - partSum[j][x - 1] - partSum[i - 1][y] + partSum[i - 1][x - 1];if (sum > maximum)maximum = sum;}}}}return maximum;}/*方法二将二维转化为一维处理,当子矩阵的上下行确定时,把上下行中每一列的数据当作一个单元,确定左右列的过程就是求以列为单元的一维数组的子数组最大和的过程*/int MaxSumTwo(int m, int n){int i, j, k;int maximum = -1000;int start, all;int B[110];for (i = 1; i <= m; i++){for (k = 1; k <= n; k++){B[k] = 0;}for (j = i; j <= m; j++){for (k = 1; k <= n; k++){B[k] += A[j][k];}start = B[n];all = B[n];for (k = n - 1; k >= 1; k--){if (start < 0)start = 0;start += B[k];if (start > all)all = start;}if (all > maximum)maximum = all;}}return maximum;}int main(){int i, j, N;while (EOF != scanf("%d", &N)){for (i = 1; i <= N; ++i){for (j = 1; j <= N; j++){scanf("%d", &A[i][j]);}}printf("%d\n", MaxSumTwo(N, N));}return 0;}

我在poj 上进行了测试,解法一耗时63MS,解法二耗时16MS

0 0