最大子矩阵和

1. 简述

    给定一个n*n(0<n<=100)的矩阵,请找到此矩阵的一个子矩阵,并且此子矩阵的各个元素的和最大,输出这个最大的值。
    Example:
     0 -2 -7  0
     9  2 -6  2
    -4  1 -4  1
    -1  8  0 -2
    最大子矩阵为:
    9 2
   -4 1
   -1 8

2. 原理

    最大子矩阵和是最大子序列和的二维扩展。
    穷举所有子矩阵的话,有C(n,2)*C(n*2)/2个子矩阵,就是n^4个子矩阵,这还不算每个子矩阵求和的时间,就到了O(n^4)。
    转化为最大子序列求解的思路是:固定第i列到第j列的范围,寻找在这个范围内的最大子矩阵,这个寻找过程,把每行第i列上的元素到第j列的元素分别求和,就转变为了一维的情况。由于有C(n,2)种列的组合,而求一维的子序列需要n的时间,所以,总体上时间复杂度为O(n^3)。

3. 递推公式

    A的下标从0开始,为了增加哨兵,F,P,Q的下标都从1开始。    
    · A[N][N]表示输入矩阵。
    · F[N+1][N+1],F[i][j]表示从第i行的第0列到第j列的元素和。
    F[i][j]=0,j=0
      F[i][j]=A[i-1][j-1], j=1
      F[i][j]=F[i][j-1]+A[i-1][j-1],j>1
      这样当固定第i列到第j列的时候,转化为一维数组的第k个元素就可以表示为F[K][j]-F[K][i-1],K是行下标,i和j都是列下标,由于矩阵的统计是从1开始的,所以i,j,k都是大于等于1的,即i-1不会下标越界,这就是前面哨兵的作用。
    固定i列和j列的时候的求解递推公式:
    · P[N+1],P[k]表示固定第i列到第j列时,从第1行到第k行范围内,包括第k行的最大子矩阵。
    · Q[N+1],Q[k]表示固定第i列到第j列时,从第1行到第k行范围内,最大子矩阵。
      P[k]=F[0][j]-F[0][i-1], k=1
      P[k]=P[k-1]>0?(P[k-1]+F[k][j]-F[k][i-1]):(F[k][j]-F[k][i-1]),k>1
      Q[k]=P[k], k=1
      Q[k]=max{Q[k-1], P[k]}, k>1
      Q[N]即为固定列(i-j)范围内的最大和。

4. 代码   

#include  < iostream >
using   namespace  std;
#define  N 4
int  main() {
  
int  A[N][N]  =  {  0 - 2 - 7 ,   0 9 2 - 6 2 - 4 1 - 4 1 - 1 8 0 - 2  }; 
  
int  F[N + 1 ][N + 1 ];
  
int  P[N + 1 ];
  
int  Q[N + 1 ];
  
int  max, index_i, index_j;
  
//  F 
   for ( int  i = 1 ; i < N + 1 ; i ++ ) {
    F[i][
0 =   0 //  第0列,即哨兵列 
    F[i][ 1 =  A[i - 1 ][ 0 ];  //  第1列 
  }
  
for ( int  i = 1 ; i < N + 1 ; i ++ ) {
    
for ( int  j = 2 ; j < N + 1 ; j ++ ) {  //  从第2列开始 
      F[i][j]  =  F[i][j - 1 +  A[i - 1 ][j - 1 ];
    }
  }
  
//  P,Q
  max  =  INT_MIN;
  
for ( int  i = 1 ; i < N + 1 ; i ++ ) {
    
for ( int  j = i + 1 ; j < N + 1 ; j ++ ) {
      P[
1 =  F[ 1 ][j] - F[ 1 ][i - 1 ];
      Q[
1 =  P[ 1 ];
      
for ( int  k = 2 ; k < N + 1 ; k ++ ) {
        P[k] 
=  P[k - 1 ] > 0 ? (P[k - 1 ] + F[k][j] - F[k][i - 1 ]):(F[k][j] - F[k][i - 1 ]);
        Q[k] 
=  Q[k - 1 ] > P[k] ? Q[k - 1 ]:P[k]; 
      }
      
if (Q[N]  >  max) {
        max 
=  Q[N];
        index_i 
=  i;
        index_j 
=  j;
      }
    }
  }
  
//  max
  cout  <<  max  <<  endl;
  cout 
<<  index_i  <<   "  ,  "   <<  index_j  <<  endl;
  system(
" PAUSE " );
  
return   0 ;

    输出结果如下:
   

5. 参考

    最大子矩阵问题    http://www.cnblogs.com/fll/archive/2008/05/17/1201543.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值