To the MAX(蓝书刷题记录)

本文探讨了三种求解最大子矩阵和的算法,包括枚举两端点的朴素算法、利用前缀和优化的算法及二维数组压缩算法,分别具有O(n^6), O(n^4)和O(n^3)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:给定一个 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值