学dp已经第十五天了,感觉自己没有多少进步。反而一天比一天焦躁。
别人最快的已经做了22个题了,而我才做了8个题。现在是一点也狂妄不起来了。。。。
不过还是稍微有点感觉了,也挺值得开心的,虽然远远不够。
总之学东西不要急,要沉下心来搞清楚原理。学DP时,我觉得把每一步写出来,或者用画图的形式画出来(推荐画图,思路比较清晰,如果实在不知道过程怎么来的就把每一步写下来),虽然可能耗费很多时间,但当你一步步看下来就会逐渐搞清楚DP的过程。
根据这周的课,我还是对这个动态规划有了一写更明确的学习方向。100道不同的dp问题。饭要一口一口吃。针对本周的题得出的想法如下;
列一
此题是对以前的题得复习如下
求一个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。
思路:
首先,这个子矩阵可以是任意大小的,而且起始点也可以在任何地方,所以,要把最大子矩阵找出来
假定原始矩阵的行数为M,那么对于子矩阵,它的行数可以是1到M的任何一个数,而且,对于一个K行(K < M)的子矩阵,它的第一行可以是原始矩阵的第1行到 M - K + 1 的任意一行。
这也就是说可以把这个理解成子问题
而且在求最大子矩阵的 时候我们可以通过以前对最大字段和问题进行类比
具体假设如下
假设这个最大子矩阵的维数是一维,要找出最大子矩阵, 原理与求“最大子段和问题” 是一样的。最大子段和问题的递推公式是 b[j]=max{b[j-1]+a[j], a[j]},b[j] 指的是从0开始到j的最大子段和。
但是这是一个二维的要找出最大子矩阵,我们要从左到右不断的遍历才能找出在这种情况下的最大子矩阵。如果我们把这两行上下相加,情况就和求“最大子段和问题” 又是一样的了
`。为了找出在原始矩阵里的最大子矩阵,我们要遍历所有的子矩阵的可能情况,也就是说,我们要考虑这个子矩阵有可能只有1行,2行,。。。到n行。而在每一种情况下,我们都要把它所对应的矩阵部分上下相加才求最大子矩阵(局部)。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int N[505][505];
memset(N,0,sizeof(N));
int n,m;
cin>>m>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>N[i][j];
N[i][j]+=N[i-1][j];
}
}
int sum,ans=0;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
sum=0;
for(int k=1;k<=m;k++)
{
sum+=N[j][k]-N[i-1][k];
if(sum<0)
sum=0;
ans=max(sum,ans);
}
}
}
cout<<ans<<endl;
return 0;
}`