1. 题目来源
链接:最强对手矩阵
相关:
2. 题目解析
非常非常经典的一道题目,最大子矩阵、最大子阵和等等…方法也是多种多样,简单罗列一下,规定行列分别为 n 、 m n、 m n、m
- 暴力: O ( n 3 m 3 ) O(n^3 m^3) O(n3m3)
- 二维前缀和: O ( n 2 m 2 ) O(n^2m^2) O(n2m2)
- 列压缩,求一维最大子段和: O ( n 2 m ) O(n^2m) O(n2m)
- 当 n > m n>m n>m 矩阵可翻转,则为 O ( n m 2 ) O(nm^2) O(nm2)
4 种做法,层层优化,对应着四种境界吧。
代码:
二维前缀和:
#include <bits/stdc++.h>
using namespace std;
const int N = 405;
int n, m;
int a[N][N], s[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> a[i][j];
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
int res = -1e9;
for (int x1 = 1; x1 <= n; x1 ++ )
for (int x2 = x1; x2 <= n; x2 ++ )
for (int y1 = 1; y1 <= m; y1 ++ )
for (int y2 = y1; y2 <= m; y2 ++ )
res = max(res, s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
cout << res << endl;
return 0;
}
列压缩,dp
,20 分能得 14 分。
#include <bits/stdc++.h>
using namespace std;
const int N = 405;
int n, m;
int a[N][N], sum[N][N], tmp[N], f[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> a[i][j];
for (int j = 1; j <= m; j ++ )
for (int i = 1; i <= n; i ++ )
sum[i][j] = sum[i - 1][j] + a[i][j];
int res = -1e9;
for (int i = 1; i <= n; i ++ )
for (int j = i; j <= n; j ++ ) {
for (int k = 1; k <= m; k ++ ) tmp[k] = sum[j][k] - sum[i - 1][k], f[k] = -1e9;
f[1] = tmp[1];
for (int q = 2; q <= m; q ++ ) f[q] = max(f[q - 1] + tmp[q], tmp[q]), res = max(res, f[q]);
}
cout << res << endl;
return 0;
}
列压缩 + dp
+ 行列转换, 20 分拿满。
来自官方题解,各种优化基本都用到了,很清楚明了的一种写法~
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
int main(){
int n,m;
cin>>n>>m;
vector<vector<int>> a(n+1,vector<int>(m+1));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
if(n>m){
vector<vector<int>> b(m+1,vector<int>(n+1));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
b[i][j]=a[j][i];
}
}
swap(n,m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
b[i][j]+=b[i-1][j];
}
}
ll ans=-0x3f3f3f3f;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ll res=0;
for(int k=1;k<=m;k++){
res=max(res,0ll)+b[j][k]-b[i-1][k];
ans=max(ans,res);
}
}
}
cout<<ans<<endl;
}else{
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]+=a[i-1][j];
}
}
ll ans=-0x3f3f3f3f;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ll res=0;
for(int k=1;k<=m;k++){
res=max(res,0ll)+a[j][k]-a[i-1][k];
ans=max(ans,res);
}
}
}
cout<<ans<<endl;
}
return 0;
}