忘掉吧,我给你一个解
https://blog.csdn.net/csyifanZhang/article/details/104827171
↑更好的阅读体验
最大和子矩阵
给定一个矩阵
0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
求出和最大的子矩阵,看到这个问题的时候,我第一时间想到的是维护二维矩阵的前缀和,然后对每个点遍历他左上方的所有矩形的前缀和,相减即为该矩阵的和,取最大值即可
#define MAX 105 #define ll int ll sum[MAX][MAX], a[MAX][MAX]; int main() { ll N; while (cin >> N) { memset(sum, 0, sizeof(sum)); for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { cin >> a[i][j]; sum[i][j] = sum[i][j - 1] + a[i][j];//按行求前缀数组 } } //按行求前缀数组 for (int j = 1; j <= N; j++) for (int i = 1; i <= N; i++) sum[i][j] = sum[i - 1][j] + sum[i][j]; ll res = 0; for (int i = 0; i <= N; i++) for (int j = 0; j <= N; j++) for (int m = i; m <= N; m++) for (int n = j; n <= N; n++) { //如果端点在一行或者一列 那么直接前缀和之差 if (m == i || n == j) res = max(res, sum[m][n] - sum[i][j]); //如果端点不同行也不同列 else res = max(res, sum[m][n] - sum[m][j] - sum[i][n] + sum[i][j]); } cout << res << endl; } }
打眼一看复杂度,剪枝也减不了多少。,应该被卡死,当然这道题并没有卡死,但是为了这个思路我还是写了
此时,我们应该想到,一维子序列的最大和数组就是在上述搜索的过程中优化得来的,那么同样的,二维应该如何进行优化呢?可不可以对每一列,我们把它与它右边的列分别相加进行组合,比如在考虑第一列的时候,我们考虑的次序分别为1,1+2,1+2+3,1+2+3+4,如果考虑第二列,那应该考虑的次序为2,2+3,2+3+4,将这些列的组合纵向相加,看例子
0 -2 -7 0 (1):0 (1+2):-2 。。。 9 2 -6 2 9 11 -4 1 -4 1 -4 -3 -1 8 0 -2 -1 7
此时如果我们纵向求最大和子序列,对(1+2)而言,就是求(1,2)两列围成的区域内,最大和子矩阵,对(1+2)求最大和子序列,显然可以得到15,也就是正确结果。
#include<iostream> #include<cmath> #include<iomanip> #include<string.h> #include<vector> #include<map> #include<queue> #include<algorithm> using namespace std; #define MAX 505 #define inf 1e9 #define ll int #define p pair<ll, ll> ll n, a[MAX][MAX], b[MAX][MAX], res; int main() { cin >> n; for (ll i = 1; i <= n; i++) for (ll j = 1; j <= n; j++) cin >> a[i][j]; res = a[1][1]; for (ll i = 1; i <= n; i++) {//从第一列开始 memcpy(b, a, sizeof(a)); for (ll j = i + 1; j <= n; j++) {//其后的第j列 for (ll k = 1; k <= n; k++) b[k][j] += b[k][j - 1]; } for (ll j = i; j <= n; j++) {//其后的第j列 res = max(res, b[0][j]); for (ll k = 2; k <= n; k++) { if (b[k - 1][j] > 0) b[k][j] = b[k - 1][j] + b[k][j]; res = max(res, b[k][j]); } } } cout << res << endl; }