动态规划之--最大子段和/最大子矩阵和

动态规划之--最大子段和/最大子矩阵和

一、最大子段和
最大子段和针对的是一维的情形,采用蛮力法可以在O ( n 2 ) O(n^2)O(n
2
)的时间复杂度内进行求解。而采用动态规划的方法则则可以在O ( n ) O(n)O(n)的时间复杂度内进行求解。这里我们着重介绍动态规划的方法。
问题描述:
对于长度为n的数组num[N],求解其最大的连续子段和m a x s u b S u m = ∑ n = i j n u m [ n ] , 其 中 有 0 ≤ i ≤ j ≤ n maxsubSum=\sum\limits_{n=i}^jnum[n],其中有0≤i≤j≤nmaxsubSum=
n=i

j

num[n],其中有0≤i≤j≤n。
解决思路:
规划规划矩阵dp[i],dp[i]表示以num[i]作为结尾元素时的最大字段和。
则有如下状态转移方程:
d p [ i ] = m a x { d p [ i − 1 ] + n u m [ i ] , n u m [ i ] } dp[i]=max\{dp[i-1]+num[i],num[i] \}
dp[i]=max{dp[i−1]+num[i],num[i]}

以上的转移方程的是显而易见的,因为要满足n u m [ i ] num[i]num[i]作为最后一个元素,因此只会存在两种情况:
①继续累加d p [ i ] = d p [ i − 1 ] + n u m [ i ] dp[i]=dp[i-1]+num[i]dp[i]=dp[i−1]+num[i]。
②另起炉灶d p [ i ] = n u m [ i ] , dp[i]=num[i],dp[i]=num[i],显然只有当dp[i-1]<0时才会考虑该种情况。

定义完以上的转移方程之后,最后的答案就是max ⁡ 0 ≤ i ≤ n d p [ i ] \max\limits_{0≤i≤n} dp[i]
0≤i≤n
max

dp[i],因为dp[i]包含了以所有元素作为结尾的所有子段和,所以只需要取里面的最大值就完事了!

#include <iostream>
#include <climits>
#define N 101
using namespace std;

int buf[N];

int max(int a,int b){return a>b?a:b;}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>buf[i];

int maxsum=INT_MIN;
int cursum=0;
for(int i=0;i<n;i++){
cursum = max(buf[i],buf[i]+cursum);//cursum[i]指的是以当前元素作为结尾时最大子段和,
//因此要么另起炉灶,要么继续累积。
maxsum = max(cursum,maxsum);
}
cout<<maxsum<<endl;
return 0;
}
/**
10
1 3 5 7 -2 9 -1 -3 -4 -5
*/

二、最大子矩阵和
最大子矩阵和是二维的情形,采用蛮力法可以在O ( n 4 ) O(n^4)O(n
4
)的时间复杂度内解决,可想而知到n>100的时候就快扛不住了,而采用动态规划算法则可以在O ( n 3 ) O(n^3)O(n
3
)的时间复杂度内解决该问题,直接降低了一个数量级。有了以上的最大子段和的算法作为铺垫之后,我们求解最大子矩阵和就方便多了。
问题描述:
对于尺寸为N × N N×NN×N的矩阵num[N][N],求解其最大的子矩阵和。
以下图为例,矩阵num的最大子矩阵如下图红框所示::

解决思路
前面已经铺垫了这个问题其实和求解最大子段和有关,那么现在的问题就在于怎么把问题从求最短子段和转换为求最大子矩阵。问题的关键就在于求最大子矩阵问题本质上就是求n*n次最大子段和的问题,试想一下,我们需要对于一维数组b[N]求解1 2 ∗ n ∗ n \frac{1}{2}*n*n
2
1

∗n∗n次的最大子段和,而每一次存储的是第i行到第j行中对应的每一列的累加和。下面画图为例:

因此现在需要做的就是把所有的i~j的情况遍历一遍,记录所有情况下的最大子段和之后,便可以得到最终的最大子矩阵和,方法也显而易见,所有的子矩阵都被我们求过了。所以只需要找到其中的最大值即可。

#include <iostream>
#include <climits>
#define N 100
using namespace std;
int buf[N][N];
int tmp[N][N];//辅助矩阵,其中tmp[i][j]存储的是前i行的第j列的累加之和
int b[N];
int max(int a,int b){return a>b?a:b;}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>buf[i][j];
}
}
for(int i=0;i<n;i++)//初始化第一行
tmp[0][i]=buf[0][i];
for(int i=1;i<n;i++){
for(int k=0;k<n;k++){
tmp[i][k]=tmp[i-1][k]+buf[i][k];//累加上一行的值求和
}
}
int maxsum = INT_MIN;
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
int cursum=0;
for(int k=0;k<n;k++){
if(i==0){
b[k]=tmp[j][k];
}
else{
b[k]=tmp[j][k]-tmp[i-1][k];//得到第i行到第j行的累加之和
}
cursum=max(b[k],b[k]+cursum);
maxsum=max(maxsum,cursum);
}
}
}
cout<<maxsum<<endl;
return 0;
}

参考博客:https://blog.csdn.net/Double2hao/article/details/51727420
————————————————
版权声明:本文为CSDN博主「Saul Zhang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37053885/article/details/88980244

 

posted @   菜鸡一枚  阅读(690)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2015-10-08 Extending Markov to Hidden Markov
点击右上角即可分享
微信分享提示