问题描述:给定一个 n*n 的矩阵,求最大子矩阵。
引发一个专题:
求最大子矩阵的方法。
方法一:最朴素的算法可以是枚举两个端点,在对其求和。复杂度O(n^6) hloj 1935护林员盖房子
方法二:预处理出前缀和 sum[i][j]表示由(1,1) 到 (i,j) 的和。
所以由 (x1,y1) 到(x2,y2) 可以O(1) 求。 即为 sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1] 。可以画图理解。 复杂度 O(n^4)
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[500][500],sum[500][500],temp[500];
int ans=-1;
// x1 y1--->x2 y2 sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]
inline int cal(int x1,int y1,int x2,int y2){ return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]),sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
for(int x2=1;x2<=n;x2++)
for(int y2=1;y2<=n;y2++)
{
for(int x1=1;x1<=x2;x1++)
for(int y1=1;y1<=y2;y1++)
ans=max(ans,cal(x1,y1,x2,y2));
}
cout<<ans;
return 0;
}
方法三: 考虑对于二维的数组进行压缩。枚举行i 和 j 。这两行之间的数压缩成 temp[k] 表示第k列上 i 到 j 的和。所以temp[] 的最大连续和即为最大子矩阵。需要预处理出sum[i][j] 表示第i 列上的前缀和。复杂度 O(n^3)
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[500][500],sum[500][500],temp[500];
int ans=-1;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
sum[j][i]=sum[j][i-1]+a[i][j];
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
for(int k=1;k<=n;k++) temp[k]=sum[k][j]-sum[k][i-1];
int s=0;
for(int i=1;i<=n;i++)
{
s+=temp[i];
if(s>ans) ans=s;
if(s<0) s=0;
}
}
cout<<ans;
return 0;
}