zoukankan      html  css  js  c++  java
  • 线性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
    ", 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
    ",mx);
    38     return 0;
    39 }
  • 相关阅读:
    java简单学习笔记20190211及以前
    java简单学习笔记20190206
    java简单学习笔记20190205
    java简单学习笔记20190202
    java学习简单笔记20190130
    java简单学习笔记20190127
    java简单学习笔记20190126
    角色用例表
    原型图
    a标签,选中当前菜单后高亮
  • 原文地址:https://www.cnblogs.com/wsy107316/p/12240646.html
Copyright © 2011-2022 走看看