zoukankan      html  css  js  c++  java
  • 动态规划笔记

    动态规划笔记

    一、基本思想

    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);
    
        }
    }
    
    
  • 相关阅读:
    Acwing 164 可达性统计 (拓扑排序+bitset)
    STL-bitset的基本用法
    Acwing 115 给树染色 (贪心)
    Acwing 112 雷达设备 (贪心)
    Acwing 110 畜栏预定 (贪心+stl)
    Acwing 110 防晒 (贪心算法)
    Acwing 七夕祭 (前缀和+中位数+思维)
    Acwing 103 电影 (map)
    USACO 最佳牛围栏 (二分答案+前缀和+双指针)
    Acwing 101 最高的牛 (差分数组)
  • 原文地址:https://www.cnblogs.com/YJBlog/p/12337104.html
Copyright © 2011-2022 走看看