一、题目大意
二、解题思想
1、TE
: 利用sum[i][j]
记录(i,j)
左上方所有的和,然后利用前缀和的思想快速求出某个矩阵的和。最后使用四重循环,但是超时。
2、AC: 使用压缩维度和动态规划思想。
(1)压缩维度
- 定义 s u m O f L i n e [ i ] [ j ] sumOfLine[i][j] sumOfLine[i][j]:为第 j j j列上前 i i i行所有数的和。使用 O ( n 2 ) O(n^2) O(n2)求出结果。
(2)动态规划:
- 最大子矩阵必定横跨某两行。
- 对任意一个横跨 [ i , j ] [i,j] [i,j]行的矩阵,我们使用 s u m O f L i n e sumOfLine sumOfLine快速将其压缩为一维,然后求这个一维数组的最大连续子序列和。
- 任意两行组合的最大值即为最终答案。
- O ( n 3 ) O(n^3) O(n3)
三、代码
#include<iostream>
#include<stdio.h>
using namespace std;
const int MAX = 105;
const int inf = 1 << 30;
int grad[MAX][MAX];
int sum_of_line[MAX][MAX];
int line[MAX];
int get_max_sequence(int n)
{
int dp[MAX];
dp[1] = line[1];
for(int i=2; i<=n; i++)
dp[i] = max(line[i], dp[i-1]+line[i]);
int res = -inf;
for(int i=1; i<=n; i++)
res = max(dp[i], res);
return res;
}
int main()
{
int n;
scanf("%d", &n);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%d", &grad[i][j]);
// ---------------计算行前缀和-----------------------------
for(int j=1; j<=n; j++)
for(int i=1; i<=n; i++)
sum_of_line[i][j] = sum_of_line[i-1][j] + grad[i][j];
// --------------------------------------------------------------
int ans = -inf;
for(int r1=1; r1<=n; r1++)
{
for(int r2=r1; r2<=n; r2++)
{
for(int j=1; j<=n; j++)
line[j] = sum_of_line[r2][j] - sum_of_line[r1-1][j];
int line_max = get_max_sequence(n);
ans = max(line_max, ans);
}
}
cout << ans << endl;
return 0;
}