从一维到二维:最大子段和和最大子矩阵和

博客先分析一维最大子段和的求解,指出暴力求解时间复杂度高,应利用动态规划思想优化,通过申请dp数组记录运算值并得到递推公式求解。接着探讨二维矩阵的最大子矩阵和问题,提出将二维降维成一维类似问题,通过列的前缀和进行列压缩完成降维,再结合一维代码求解。

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

上几篇博客我们讲到了最大子段和,我们根据动态规划的思想,是可以得到其的递推公式。

下面我们先分析关于一维的最大字段和的求解过程:

如果给定一个数组 a[n],求其最大的子段。那么,我们会很容易的想到,运用暴力求解的方式,通过二维的遍历。但是其时间复杂度是O(n*n),显然当数据规模很大时,其肯定时tle的。

所以应该利用动态规划的思想进行优化,那么优化如何着手呢。我们仍然回归到暴力求解方法中去,暴力方法就是将子段的所有的情况都列举出来,并且一一相加求和,最后得出了最大值。例如此数组有四个元素,那么子段的情况可能是(a[0],a[1])、(a[0],a[2])、(a[0],a[1],a[2]),等等。我们可以发现,计算机其实执行了许多的重复操作。但我们列举的数组长度是从小到大时,其实到了最后我们计算长数组值时,有计算了一遍小数组的值,如上面的例子。所以这就是我们优化的方向,它也满足了动态规划的基本特征,就是其有多个重复的子问题。那么我们可以以空间换时间,申请空间,记录计算机运算过的值。

延续思路,我们可以申请dp数组,同时我们可以得到递推公式:dp[i]=max(dp[i-1]+a[i],a[i]),最后我们再从dp数组中,挑出最大的。就完成了问题的求解。

ok,我们大致分析了一维的最大子段和,那么我们来解决关于二维矩阵的最大子矩阵和。

解决二维问题,我们可以将其降维,我们能否找到一种措施,使其降维成一维的类似问题?

例题如下:

求一个M*N的矩阵的最大子矩阵和。
比如在如下这个矩阵中:
 0 -2 -7  0
 9  2 -6  2
-4  1 -4  1
-1  8  0 -2 
拥有最大和的子矩阵为:
 9 2
-4 1
-1 8
其和为15。

 

我们可以发现,关于一维的最大子段和问题解决得基础是dp数组得不断延伸,就是dp数组通过前一状态不断得到现在状态的最有情况。这也是二维问题解决的基础。我们可以通过列的前缀和进行列的压缩,使得一竖列累加变为一个值,这样一个小矩阵就变成了一个数组。这也就完成了,降维的操作。最后根据一维的代码可以完成后续的操作。

#include<iostream>
using namespace std;
int main(){
    int n,m;
    cin >> n >> m;
     long long a[n+1][m+1];
	long long pre[n][m];
	long long  ans=-1e9;
	long long sum;
	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++){
			ans=max(ans,a[i][j]);
		}
	}
    if(ans<0){
        
        cout << ans;
    }
    
	else{
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++)
				pre[i][j]=pre[i-1][j]+a[i][j];//压缩整个j列
				 
			}
			for(int i=1;i<=n;i++){//不断的变换上下界,
				for(int j=i;j<=n;j++){
					sum=0;
					for(int k=1;k<=m;k++){//这里并没有到dp数组,因为我们用了ans,其是动态的,一直保持现在的最大值。然而dp数组,最后需要遍历找出其最大值。思想上大同小异。
						if(sum+pre[j][k]-pre[i][k]<0)
							sum=0;
						else{
							sum+=pre[j][k]-pre[i][k];
							ans=max(ans,sum);
						}
					}
				}
			}
		
        cout << ans ;
	}
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值