动态规划笔记

动态规划笔记

一、基本思想

  1. 是将带求解的问题分解成若干个子问题,先求子问题,然后子问题的解得到原问题的答案
  2. 与分治法的不同的是 : 适用于动态规划求解的问题,经分解得到的问题往往不是互相独立
  3. 动态规划算法适用于解最优化的问题:
    • 找出最优解的性质,并刻画其结构特征
    • 递归定义最优值
    • 自底向上的方式计算出最优值
  4. 而 使用动态规划求解最优解问题,必须满足,最优解的每个局部解也都是最优的
  5. 每个动态规划的问题都是从一个网格开始的

二、0-1背包问题

问题: 背包 大小为 4,,,有三件物品 价值和重量,物品2(3000,4)物品3(2000,3)物品1(1500,1),计算最大价值

1. 首先了解基本思想:

  1. 要想解决大背包的问题,
  2. 那么先解决小背包的问题
  3. 建立网格
  4. 了解执行过程,得出每个单元格的计算公式

2. 网格和执行过程

  1. 首先计算 物品1 放入背包,产生的最大价值
    • 并且假定只能放入物品1 可以选择
物品不同容量的背包 1 2 3 4
物品1 1500 1500 1500 1500
物品2
物品3

原来的问题是要求容量为4的背包,为什么还有算 1,2,3 容量的问题 : 动态规划,就是从小问题来推导出大的问题的答案,而背包问题的小问题,就是小背包

则由上面表格得出: 应该选择1500 的物品1 ,是最大价值

  1. 然后计算第二行,放入背包的可以有物品1,和物品2 。
物品不同容量的背包 1 2 3 4
物品1 1500 1500 1500 1500
物品2 1500 1500 1500 3000
物品3
  • 因为物品2 是 3 大小,故 前面 的小背包还是放入 物品1 产生最大值,而在 容量 4 的背包的最大价值为 3000,为最新的最大价值
  1. 三个物品都能够放入
    物品不同容量的背包 1 2 3 4
    物品1 1500 1500 1500 1500
    物品2 1500 1500 1500 3000
    物品3 1500 1500 2000 3500

可以得出 最终答案为 3500 为最大价值

但是有个问题: : 这里 0-1背包问题的最优解 : 是在 表格最后这里,但是不代表每一个动态规划的算法,最优答案都是在这个,。

3. 得出单元格的计算公式

								-  上一个单元格的值(即cell[i-1][j]的值

cell[i][j] = 两个中较大的那个					VS

								- 当前商品的价值 + 剩余空间的价值 (cell[i-1][j - 当前商品的重量]

4.贴出书中的答案:仅供参考

int knapSack(int n ,int w[] , int v[]){
    for(int i= 0; i<= n; i++){
        V[i][0] = 0;
    }
    for(j = 0; j<= C; j++){
        V[0][j] = 0;
    }
    for (i=1; i<=n; i++)   //计算第i行,进行第i次迭代
           for (j=1; j<=C; j++)
                  if (j<w[i])   V[i][j]=V[i-1][j];         
                  else   V[i][j]=max(V[i-1][j], V[i-1][j-w[i]]+v[i]);

     j=C;    //求装入背包的物品
     for (i=n; i>0; i--){
         if (V[i][j]>V[i-1][j]) {
              x[i]=1;
              j=j-w[i];
         }
         else x[i]=0;
     }
     return V[n][C];    //返回背包取得的最大价值

}

5. 如果不至是三个物品,还有一个0.5大小的物品

那么你需要考虑的粒度更新,因此必须调整网格

例如:

背包大小 分为 : 0.5 , 1 , 1.5 , 2 , 2.5 , 3 , 3.5 , 4

三、编辑距离问题

问题描述: 设A和B是2 个字符串,要用最少的字符操作将字符串A转换为字符串b,,计算他们的编辑距离

fxpimu 

xwrs


输出 5

1. 网格和执行过程

而单元格 现在代表的是,第一个字符串的前i个字母 和第二字符串 的前j个字母需要编辑的次数

1 2 3 4
1 1 2 3 4
2 1 2 3 4
3 2 2 3 4
4 3 3 3 4
5 4 4 4 4
6 5 5 5 5

2. 得出单元格的计算公式

 if (n.charAt(i - 1) == m.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                    System.out.println(i+"-"+j+"->" + dp[i][j]);
 }else {
                    dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
                   System.out.println(i+"-"+j+" ->" + dp[i][j]);
                }

3. 参考算法

package book.practices.code;

/**
 * @version : 1.0
 * @auther : Firewine
 * @Program Name: code32
 * @Create : 2019/12/28
 * @Description :
 */
public class code32 {

    /**
     * 编辑距离问题
     * fxpimu
     * xwrs
     *
     *
     *
     * 输出5
     *
     *
     * 状态定义:Fi,j表示第一个字符串的前i个字母和第二个字符串的前j个字母需要编辑的次数,
     * 求Fn,m,n和m分别是两个字符串的长度。
     *
     * 状态转移方程:
     * 当Fi,j-1=Fi-1,j时,Fi,j=Fi,j-1;
     * 当Fi,j-1!=Fi-1,j时,Fi,j=min{Fi-1,j-1,Fi,j-1,Fi-1,j}+1.
     */

    private  void solve (String n,String m){
        int  aLen = n.length();
        int  bLen = m.length();

        int[][] dp  = new int[aLen+1][bLen+1];
        for (int i= 0; i< aLen+1;i++){
            dp[i][0]=i;
        }
        for (int i = 0;i < bLen+1;i++){
            dp[0][i] = i;
        }
        //开始状态运算
        for (int i = 1; i < aLen+1; i++) {
            for (int j = 1; j<bLen+1;j++){
                if (n.charAt(i - 1) == m.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                    System.out.println(i+"-"+j+"->" + dp[i][j]);
                }else {
                    dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
                   System.out.println(i+"-"+j+" ->" + dp[i][j]);
                }
            }
        }
        System.out.println(dp[aLen][bLen]);
    }


    public static void main(String[] args) {

        code32 demo = new code32();
        String n = "fxpimu";
        String m = "xwrs";
        demo.solve(n,m);

    }
}

原文地址:https://www.cnblogs.com/YJBlog/p/12337104.html