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 }

 

posted @ 2021-02-23 19:42  acmloser  阅读(44)  评论(0编辑  收藏  举报