Calculate the biggest sum of submatrix

 Let's continue the topic discussed in last article. What if we want to calculate the biggest sum of the submatrices of a matrix, which can be treated as a 2-D array? The usual idea is that we can solve this problem by "reducing" the "size" of the problem, that is, reduce 2-D to 1-D, and then, we have already the solution of linear complexity at hand. So how to reduce the problem? Here is one way: 1. Choose an upper and a lower bound of lines and treat every fragment of the columns within these bounds as a whole, which means only the sum of that fragment is taken into consideration; 2. Enumerate the upper and lower bounds and repeat the 1st step. Finally we can get the biggest sum of submatrix (as well as the starting and ending elements' line indices and column indices). Let's look closer. The 2nd step is a m*n loop, where m is the number of lines and n is the number of columns of the original matrix. To calculate biggest sum of 1-D array is of complexity O(n), where n is the number of array elements. Thus the total complexity of this process is O(m*n*n')*(the complexity of calculate the sum of column fragments) (here n' = n). In the code shown below, a small trick trading space cost off time cost is used to make the complexity of summing the column fragments be O(1) and thus the total complexity is O(m*n*n).

 

  1. #include <iostream>
  2. using namespace std;
  3. // Calculate the sums of the column fragments.
  4. int* partial_sums_of_matrix(int* A, int m, int n) {
  5.     // Allocate matrix P.
  6.     int new_m = m + 1, new_n = n + 1;
  7.     int* P = new int[new_m * new_n];
  8.     // Initialize matrix P.
  9.     for(int i = 0; i < new_m; ++i) { // Zero the left-most column.
  10.         *(P+i*new_n) = 0; // *(P+i*new_n+0) = 0;
  11.     }
  12.     for(int i = 0; i < new_n; ++i) { // Zero the up-most line.
  13.         *(P+i) = 0; // *(P+0*new_n+i) = 0;
  14.     }
  15.     // Calculate the sums of column fragments of matrix A and Store them in matrix P.
  16.     for(int i = 1; i < new_m; ++i) {
  17.         for(int j = 1; j < new_n; ++j) {
  18.             *(P+i*new_n+j) = *(P+(i-1)*new_n+j) + *(P+i*new_n+(j-1)) - *(P+(i-1)*new_n+(j-1)) + *(A+(i-1)*n+(j-1)); // !Notic here: NOT *(A+i*n+j)!
  19.         }
  20.     }
  21.     return P;
  22. }
  23. // Get the partial sum of a particular submatrix region.
  24. inline int get_a_partial_sum(int* P, int tmint bm, int on, int cn) {
  25.     return *(P+bm*on+cn) - *(P+bm*on+(cn-1)) - *(P+(tm-1)*on+cn) + *(P+(tm-1)*on+(cn-1));
  26. }
  27. // Calculate max sum of subarray of 1-D arrays (just the same as shown in last article).
  28. int max_sum_of_subarray(int* A, int n, int& start_index, int& end_index) {
  29.     int max_all, max_pre; // Store the max sum of the pre-subarray.
  30.     int temp_start_index, temp_end_index; // Bookkeeping during the process.
  31.     max_pre = max_all = A[0];
  32.     temp_start_index = temp_end_index = start_index = end_index = 0;
  33.     for(int i = 1; i < n; ++i) {
  34.         if(A[i] > max_pre + A[i]) { // A new "bigger" subarray appears.
  35.             max_pre = A[i];
  36.           temp_start_index = temp_end_index = i;
  37.         }
  38.         else { // Just add the ith element into the old subarray.
  39.             max_pre += A[i];
  40.             temp_end_index = i;
  41.         }
  42.         if(max_all < max_pre) { // Adjust the final max sum and the indices.
  43.             max_all = max_pre;
  44.             start_index = temp_start_index;
  45.             end_index = temp_end_index;
  46.         }
  47.     }
  48.     return max_all;
  49. }
  50. // Calculate max sum of submatrix of 2-D matrices.
  51. int max_sum_of_submatrix(int* P, int m, int n, int& start_m, int& start_n, int& end_m, int& end_n) {
  52.     int max_pre, max_all = 0x80000000;
  53.     int temp_start_m, temp_start_n, temp_end_m, temp_end_n;
  54.     int* temp_p = new int[n];
  55.     for(int t = 1; t < m; ++t) {
  56.         temp_start_m = t - 1; // temp_start_m is the starting line index of the original matrix.
  57.         for(int b = t; b < m; ++b) {
  58.             temp_end_m = b - 1; // temp_end_m is the starting line index of the original matrix.
  59.             for(int j = 1; j < n; ++j) { // Put the partial sums in a 1-D array.
  60.                 temp_p[j] = get_a_partial_sum(P, t, b, n, j);
  61.             }
  62.             // Calculate 1-D.
  63.             // temp_start_n and temp_end_n are the ending element's indices of the original matrix.
  64.             max_pre = max_sum_of_subarray(temp_p+1, n-1, temp_start_n, temp_end_n);
  65.             if(max_pre > max_all) {
  66.                 max_all = max_pre;
  67.                 start_m = temp_start_m;
  68.                 start_n = temp_start_n;
  69.                 end_m = temp_end_m;
  70.                 end_n = temp_end_n;
  71.             }
  72.         }
  73.     }
  74.     delete[] temp_p;
  75.     return max_all;
  76. }
  77. void print_matrix(int* A, int m, int n) {
  78.     for(int i = 0; i < m; ++i) {
  79.         for(int j = 0; j < n; ++j) {
  80.             cout << *(A + i * n + j) << " ";
  81.         }
  82.         cout << endl;
  83.     }
  84. }
  85. int main() {
  86.     int A[3][5] = {
  87.         {-2, 4, 1, 6, -7},
  88.         {3, 5, 1, -8, 0},
  89.         {10, -9, 2, 0, -3}};
  90.     int* P = partial_sums_of_matrix(&A[0][0], 3, 5);
  91.     int max_sum, start_m, start_n, end_m, end_n;
  92.     max_sum = max_sum_of_submatrix(P, 3+1, 5+1, start_m, start_n, end_m, end_n);
  93.     cout << "max sum: " << max_sum << "/trange: [" << start_m << ", " << start_n << "], [" << end_m << ", " << end_n << "]" << endl;
  94.     return 0;
  95. }

The output is like this:

max sum: 15        range: [0, 0], [2, 2]

 

Similarly, we can also enumerate the left and right bounds with the sums of line fragments to get the final biggest sum of submatrix, and the complexity becomes O(m*n*m). If m and n are of the same scale, there is little difference. Otherwise we need to find the smaller of the two to get the most efficient process. In a word, the complexity is O(m*n*min(m, n))).

 

Referenced to <Beauty of Programming>.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值