您的位置:首页 > 其它

动态规划--最大子矩阵和

2017-11-06 19:20 260 查看
一、原理分析

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

表示输入矩阵。


    · 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
即为固定列(i-j)范围内的最大和。


二、代码实现

#include <bits/stdc++.h>

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, -}; 

  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;

  return 0;

} 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: