DP问题各种模型的状态转移方程

1(最长公共子串(注意和最长公共子序列区别))

两个字符串str1和str2,长度分别为(l1,l2)

dp[i][j]表示以两个字符串分别以第i和第j个字符结尾所能达到的公共子序列的长度,由于下面涉及到i-1和j-1,那么这个时候我们一般从i=1和j=1开始到i<=len1, j<=len2。

       if(str[i-1]=str[j-1])

            dp[i][j]=dp[i-1][j-1]+1;

        if(str[i-1]!=str[j-1])

            dp[i][j]=0;

2.(数塔问题)

给定一个数组s[n][m]构成一个数塔求从最上面走到最低端经过的路径和最大

我么采用至底向上的思路求解问题(注意从倒数第二行开始)

dp[i][j]表示走到第i行第j个的最大值

那么就有dp[i][j]=max{dp[i-1][j-1],dp[i-1][j]}+s[i][j];

for(i=n-1;i>=1;i--){ for(j=1;j<=i;j++){ dp[i][j]=max{dp[i-1][j-1],dp[i-1][j]}+s[i][j]

     }

}

最后dp[1][1]即为最大值

3.(01背包问题)

有N件物品和一个容量为V的背包。第i件物品的体积是v[i],价值是c[i]。求解将哪些物品装入背包可使价值总和最大。

我们知道对于没一件物品我们有两种可能就是放与不放

dp[i][j]表示第i件物品放入容量为j的背包所得的最大价值

dp[i][j]=max{dp[i-1][j-v[i]]+c[i],dp[i-1][j]};

这里我们从j=V倒推回来的话可以优化成

dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

核心代码:

fori=1;i<=n;i++){ for(j=V;j>=0;j--){ if(j>=v[i]) dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

       }

}

dp[v]即为最大的价值

4.(完全背包问题)

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是c[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

这时候对于没见物品就不是放与不放的问题了,而是放0件1件…….

这时候我们可以像01背包一样

dp[i][j]表示容量为j的背包第i件物品是否要再一次放入所以我们要从0-V顺序循环

dp[i][j]=max{dp[i-1][j-v[i]]+c[i],dp[i-1][j]}(注意这里和01背包一样但是求解的过程不同)

优化后:dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

核心代码:

            for(i=1;i<=n;i++){

                      for(j=v[i];j<=v;j++){//注意这里是从v[i]开始到V

                           if(j>=v[i])

                              dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

                      }

              }

注意这列求出的dp[v]是最大的因为一直叠加

5.(多重背包问题)

有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。

重点:令dp[i][j]表示前i种物品恰放入一个容量为j的背包的最大价值

状态转移方程:dp[i][j]=max{dp[i-1][v-k*v[i]]+k*c[i]|0<=k<=n[i]};(k表示第i种物品放入k件);

核心代码:

       for(i=1;i<=n;i++){

                    for(j=v;j>=0;j--){

                         for(k=1;k<=n[i];k++){

                             if(j>=k*v[i])

                                dp[i][j]=max(dp[i-1][v-k*v[i]]+k*c[i])
                         }

                    }

6.
最长公共子序列:

根据最长公共子序列问题的性质,我们可以规定dp[i][j]为字符串1的前i个字符和字符串2的前j个字符的最长公共子序列的长度, 由于下面涉及到i-1和j-1,那么这个时候我们一般从i=1和j=1开始到i<=len1, j<=len2。

1.ch1[i-1] = ch2[j-1] ,那么dp[i][j]= dp[i-1][j-1] + 1;
2. ch1[i-1] != ch2[j-1] ,那么我们知道ch1[i]和ch2[j]不可能在同一个公共子序列里出现,那么这个时候的最长的子序列可能以ch1[i]或ch2[j]结尾,那么由于dp[i][j]=max {dp[i-1][j] , dp[i][j-1]};

就有

dp = dp[i][j] = dp[i-1][j-1] + 1; i > 0且j> 0 且ch1[i-1]=
ch2[j-1];
dp[i][j]= max {dp[i-1][j] , dp[i][j-1]};i > 0且j> 0且ch1[i-1]!= ch2[j-1];

7.
(最大子段和问题(最大子序列的和不同))

给定一个序列为a1,a2,a3……an;

要求:求出这个序列里面找到一个子段和最大

dp[i]表示以第i个元素结束,求出所有的“以第i个元素结束的连续数组最大和dp[i]

就有:

       1如果dp[i-1]>0,无论ai为何值,有dp[i]=dp[i-1]+ai;

       2如果dp[i-1]<=0;舍弃,重新令dp[i]=ai;(因为dp[i-1]为负数无论ai为什么值加上去都会减少)

       状态转移方程:dp[i]=dp[i-1]+ai (dp[i-1]>0)

                               dp[i]=ai(dp[i-1]<=0)

8.
(最大m子段和)

在限制条件增加一维时,可以将状态也相应的增加一维,来进行状态转移

以dp[i][j]表示以第i个元素为结尾,使用j个子段所能达到的最大值(这一维的状态,正是对应了新的限制条件!)这样就很容易写出

状态转移方程:

            dp[i][j]= max{ dp[i - 1][j] + a[i], dp[i - k][j - 1] + a[i]}( j - 1 <= k <n - m + j).

            1  dp[i - 1][j] + a[i] (把第i个元素包含在最后一个子段内)

            2  dp[i - k][j - 1] + a[i], j - 1 <= k < n - m + j(第i个元素单独为一子串)
    原文作者: 汉诺塔问题
    原文地址: https://blog.csdn.net/sun897949163/article/details/49559679
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞