线性DP之最大和问题
【最长子序列和】
问题定义:对于给定序列 a1,a2,a3……an 寻找它的某个连续子段,使得其和最大。
模板:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 110; 5 const int inf=0x3f3f3f3f; 6 7 int main() 8 { 9 int a[maxn], n; 10 cin>>n; 11 for(int i=1; i<=n; i++){ 12 cin>>a[i]; 13 } 14 int dp[maxn]; 15 dp[0] = 0; 16 for(int i=1; i<=n; i++){ 17 dp[i]=max(dp[i-1]+a[i], a[i]);///状态转移方程,表示以第i个数结尾的连续子序列的最大和 18 } 19 int maxs = -inf; 20 for(int i = 1; i <= n; i++) 21 { 22 if(maxs<dp[i]) 23 maxs=dp[i]; 24 } 25 cout<<maxs<<endl; 26 return 0; 27 }
【数字三角形】
给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。
对于给定的由n行数字组成的数字三角形,计算从三角形的顶至底的路径经过的数字和的最大值。
模板:
1 /* */ 2 # include <bits/stdc++.h> 3 # include <iostream> 4 # include <cstdio> 5 # define Max(a, b)(a>b?a:b) 6 using namespace std; 7 8 int main() 9 { 10 long long int a[101][101]; 11 int D[101][101]; 12 int n, i, j; 13 scanf("%d", &n); 14 for( i=1; i<=n; i++ ) 15 { 16 for( j=1; j<=i; j++ ) 17 { 18 scanf("%d", &D[i][j]); 19 } 20 } 21 for( i=1; i<=n; i++ ) 22 { 23 a[n][i] = D[n][i]; 24 } 25 for( i=n-1; i>=1; i-- ) 26 { 27 for( j=1; j<=i; j++ ) 28 { 29 a[i][j] = max(a[i+1][j], a[i+1][j+1]) + D[i][j]; 30 } 31 } 32 printf("%lld\n", a[1][1]); 33 return 0; 34 }
【最大子矩阵和】
我们都知道在一维情况下求最大连续子序列和的操作:
1 for(int i=1;i<=n;i++){ 2 dp[i]=max(a[i],dp[i-1]+a[i]); 3 }
那么该怎么推广到二维情况下呢:(比如样例)
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
步骤:
(1)求矩阵大小是1*k(k=1,2,3,4)
可以发现就是求每行的最大连续子序和
0 -2 -7 0 (ans=0,矩阵为[0])
9 2 -6 2 (ans=11,矩阵为[9 2])
……
(2)求矩阵大小是2*k(k=1,2,3,4)
这时我们可以在第1,2行或2,3行或3,4行找最大矩阵
对于矩阵:
0 -2 -7 0
9 2 -6 2
来说,最大矩阵是
因为我们取的是矩阵,肯定是竖着一列都取的,不可能这一列取到第i个元素,上一列取到第i-1个元素,这样我们就可以把要求的两行,两两加起来
9 0 -13 2
这样求出的最大连续子序和是9,这个结果也就是这个矩阵对应的最大矩阵和。
同理把
9 2 -6 2
-4 1 -4 1
和
-4 1 -4 1
-1 8 0 -2
也分别加起来,三种情况下求出的最大值,就是2*k大小矩阵的最大值
(3)同理,我们求3*k,4*k
模板:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 110; 5 6 int a[maxn][maxn];///原矩阵 7 int b[maxn][maxn];///b[i][j]表示从某一行加到第j行第k列的列项和 8 int dp[maxn];///dp[i]表示以i列为结尾的最大矩阵和 9 int mx=0, n; 10 11 void solve(int j){ 12 memset(dp,0,sizeof(dp)); 13 for(int i=1;i<=n;i++){ 14 dp[i] = max(b[j][i], dp[i-1]+b[j][i]); 15 mx = max(mx,dp[i]); 16 } 17 } 18 19 int main() 20 { 21 scanf("%d",&n); 22 for(int i=1;i<=n;i++){ 23 for(int j=1;j<=n;j++){ 24 scanf("%d",&a[i][j]); 25 } 26 } 27 28 for(int i=1;i<=n;i++){///从第i行开始加 29 memset(b,0,sizeof(b)); 30 for(int j=i;j<=n;j++){///加到第j行 31 for(int k=1;k<=n;k++){///第j行各列的值 32 b[j][k] = a[j][k]+b[j-1][k]; 33 } 34 solve(j); 35 } 36 } 37 printf("%d\n",mx); 38 return 0; 39 }