AcWing 126. 最大的和
考察:线性dp or 暴力枚举
思路一:
预处理前缀和,四个for循环枚举边界.
思路二:
55. 连续子数组的最大和 根据这道题的思路,f[i]定义为以i结尾的最大连续和,集合划分分为长度为1和长度>1, 当长度为1 状态转移方程为f[i] = a[i],当长度>1,说明至少包含i,为f[i-1]+a[i].在两者种取最值即可f[i] = max(f[i-1]+a[i],a[i]).
那么这道题同理,设置f[i]为以第i列结尾的最大子矩阵和.f[j] = max(f[j-1]+w[i][j]-w[k-1][j],w[i][j]-w[k-1][j]).每次枚举列时要重新给f数组赋值.为什么不是二维数组呢,因为f[i-1][k]与f[j][k]的最大矩阵不一定在同一列上.for循环枚举的边界就是将这边界中的值看成一维数组的数字.
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 const int N = 110; 5 int n,mp[N][N],f[N]; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++) 10 for(int j=1;j<=n;j++) 11 scanf("%d",&mp[i][j]),mp[i][j]+=mp[i-1][j]; 12 int ans = -0x3f3f3f3f; 13 for(int i=1;i<=n;i++) 14 for(int k=1;k<=i;k++) 15 { 16 for(int j=1;j<=n;j++) f[j] = -0x3f3f3f3f; 17 for(int j=1;j<=n;j++) 18 {//先枚举i,k求出k~i行连续子序列和. 这样就保证了j-1与j是同一行的最值 19 int w = mp[i][j]-mp[k-1][j];//每次将f[j]最小,是为了求出不同i~k下的最大值 20 f[j] = max(f[j-1]+w,w);//否则上一次枚举的k会影响下一次的k 21 ans = max(ans,f[j]); 22 } 23 } 24 printf("%d\n",ans); 25 return 0; 26 }