现在的位置: 首页 > 综合 > 正文

最大子矩阵和(To The Max)

2013年03月08日 ⁄ 综合 ⁄ 共 3064字 ⁄ 字号 评论关闭

 

Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1 x 1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.

As an example, the maximal sub
-rectangle of the array:

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2

is in the lower left corner:

9 2
-4 1
-1 8

and has a sum of 
15.

The input consists of an N x N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two
-dimensional array. This is followed by N 2 integers separated by whitespace (spaces and newlines). These are the N 2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].

Output
Output the sum of the maximal sub
-rectangle. 
Sample Input
4
0 -2 -7 0 
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
Sample Output
15

提交代码如下(仅供参考):

#include <stdio.h>

#define MAX 130

int maxSum(int b[], int n)
{
    
int max = b[0];
    
int sum = 0;
    
for(int i = 0; i < n; ++i)
    
{
        
if(sum < 0) sum = b[i];
        
else sum += b[i];
        
if(sum > max) max = sum;
    }

    
return max;
}


int solve(int a[][MAX], int n)
{
    
int b[MAX];
    
int i,j,k,sum,tmp;
    sum 
= a[0][0];
    
for(i = 0; i < n; ++i)
    
{
        
for(k = 0; k < n; ++k) b[k] = 0;
        
for(j = i; j < n; ++j)
        
{
            
for(k =0; k < n; ++k) b[k] += a[j][k];
            
if(sum < (tmp = maxSum(b,n)) ) sum = tmp;
        }

    }

    
return sum;
}


int main()
{
    
int arr[MAX][MAX];
    
int i,j,n;
    
while(scanf("%d",&n)!=EOF)
    
{
        
for(i = 0; i < n; ++i)
            
for(j = 0; j < n; ++j)
                scanf(
"%d",&arr[i][j]);
        printf(
"%d ",solve(arr,n));
    }

    
return 0;
}

最大子矩阵和,即在一个n*m的矩阵中找出其子矩阵其和最大,如果直接枚举每一个子矩阵是不现实的,为了简化计算的过程,可以对矩阵进行转换...

一个子矩阵是由原矩阵中的行列组成,在求解的过程中只要找出其最大的和,在查找一维矩阵(即一维数组)时,求n个元素的和最大的子区间,我们采用的思想是扫描这一维矩阵,用max表示出现的和的最大值,sum表示从左至右的求和的值,我们要考虑sum值出现的情况,如果sum < 0这种求和是没有意义的,因为任何数加上一个小于0的负数其值必然减少,也就是这时是不可能出现最大的值,这样就可以采用将要加上的元素值赋给sum,以该点做为下一个求和的开始...,还有一点就是在使用sum计算求和时,我们只有在扫描所有元素才知道出现子区间和的最大值是什么,也就是只要为sum>0情况则再加上一元素,该元素的值必然会增大,也就是有可能出现sum的值变大出现sum > max的情况,虽然也会出现sum减少的情况,但是我们始终有max记录在求和过程中出现过的最大值,如果max < sum则更新max的值,最终的max便是我们要求的一维矩阵的最大值

 

int maxSum(int b[], int n)
{
    
int max = b[0];
    
int sum = 0;
    
for(int i = 0; i < n; ++i)
    
{
        
if(sum < 0) sum = b[i];
        
else sum += b[i];
        
if(sum > max) max = sum;
    }

    
return max;
}

有了一维的基础,这样就可以,扩展到二维矩阵,要想一个子矩阵的和值最大,那么其子子矩阵的和必然也是在子矩阵中的和最大的,这样就可以通过将i行转为1行,即将二维矩阵转为一维,这样就可以通过求一维的方法来处理二维的矩阵,使用循环控制子矩阵的开始行位置并累加出以此行产生出的子矩阵的和将i*m的子矩阵转为1*m的子矩阵,使maxSum求出1*m的矩阵中的出现的最大值...

 

for(i = 0; i < n; ++i)
    
{
        
for(k = 0; k < n; ++k) b[k] = 0;
        
for(j = i; j < n; ++j)
        
{
            
for(k =0; k < n; ++k) b[k] += a[j][k];
            
if(sum < (tmp = maxSum(b,n)) ) sum = tmp;
        }

    }

 

抱歉!评论已关闭.