dp例题03. 最大子矩阵和
题目Description:
给出一个矩阵, 求子矩阵(可以是其本身)数之和的最大值
Input:
第一行 为行数n和列数m (n≤500, m≤500)
接下来为一个n行m列的矩阵 (每个值ai,−1000 ≤ ai ≤ 1000)
Output:
子矩阵(可以是其本身)数之和的最大值
Sample Input:
4 4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
Sample Output:
15
解题思路:
解法1:单纯用二维前缀和 时间复杂度O(n*n*m*m);(TLE)
解法2:dp+前缀和 时间复杂度O(n*n*m) 或O(n*m*m)
如果是求一维的最长子序列 我们会用O(n)的时间复杂度求出
而这里为二维的, 能否用一维的解法思想去转化一下?
刚开始从行数遍历(不裁剪列数情况下)所有的子矩阵, 需要O(n²)时间, 之后对于这样遍历的子矩阵进行求解最大和,能否利用O(m)时间完成求解
遍历后的二维子矩阵可以一维数组化(即 将 单列上的数相加为一个数, 构造出plus数组), 再利用求一维最长子序列的思想(O(m)时间复杂度)即可
构造plus数组:利用每一列上的前缀和, 比如求第 k 列上第 i 行到第 j 行的数之和 plus[k] = col_sum[j][k] - col_sum[i-1][k]; O(1) 时间复杂度
单独构造col_sum数组: O(n*m)时间复杂度
以下为c语言代码(解法2)
1 #include <stdio.h> 2 int a[501][501], col_sum[501][501]; 3 int max_subsequence(int * a, int n) { 4 int sum = -1e7, max = -1e7; 5 for (int i = 0; i < n; i++) { 6 sum = (sum + a[i] > a[i])? sum + a[i] : a[i]; 7 max = (sum > max)? sum : max; 8 } 9 return max; 10 } 11 int main() { 12 int row, col, plus[501]; 13 scanf("%d%d", &row, &col); 14 for (int i = 0; i < row; i++) { 15 for (int j = 0; j < col; j++) { 16 scanf("%d", &a[i][j]); 17 } 18 } 19 for (int j = 0; j < col; j++) { 20 for (int i = 0; i < row; i++) { 21 if (i == 0) { 22 col_sum[i][j] = a[i][j]; 23 } 24 else { 25 col_sum[i][j] = col_sum[i-1][j] + a[i][j]; 26 } 27 } 28 } 29 int ans = -1e7; 30 for (int i = 0; i < row; i++) { 31 for (int k = i; k < row; k++) { 32 if (i == 0) { 33 for (int j = 0; j < col; j++) { 34 plus[j] = col_sum[k][j]; 35 } 36 int temp = max_subsequence(plus, col); 37 ans = (temp > ans) ? temp : ans; 38 } 39 else { 40 for (int j = 0; j < col; j++) { 41 plus[j] = col_sum[k][j] - col_sum[i-1][j]; 42 } 43 int temp = max_subsequence(plus, col); 44 ans = (temp > ans) ? temp : ans; 45 } 46 } 47 } 48 printf("%d\n", ans); 49 return 0; 50 }
浙公网安备 33010602011771号