10-11数据结构与算法-10(动态规划篇1)

一个例子

1.描述


image.png

对于方程的描述
1.当物品或者容量某一项为空,装入的最大价值都为0
2.当遍历到第i类商品的重量大于给出的容量时,是无法装入第i类商品,因此沿用上一个过程的装入策略 即:w[i] > j v[i][j] = v[i-1][j]
3.当遍历到第i类商品的重量是小于给出的容量时,就可以装入第i类商品,理解v[i-1][j-w[i]]
装入前i-1类商品到剩余的空间(容量)-->j-wi,->解释是在剩余空间下i-1中类型商品情况下的选择策略 max{}理解为比较与上一个策略的容量,要此次策略要采取的..

public class DynamicProgramming {


    /*01背包问题
     * 分别有三个物品 要存放到背包(重量为4)中 计算最大的价值
     * 重量:1 4 3
     * 价值:1500 3000 2000
     * 动态规划例题
     * */
    public static void main(String[] args) {
        int[] hight = new int[]{1, 2, 3};
        int[] value = new int[]{1500, 3000, 2000};
        int n = 4;//背包的容量
        int m = value.length;//物品的个数
        //设置一个二维数组表示总价值 加一表示 物品或者容量为0情况
        int[][] val = new int[m + 1][n + 1];
        for (int i = 0; i < val.length; i++) {
            val[i][0] = 0;
        }
        for (int i = 0; i < val[0].length; i++) {
            val[0][i] = 0;
        }
        for (int i = 1; i < val.length; i++) {
            for (int j = 1; j < val[0].length; j++) {
                if (hight[i - 1] > j) {
                    //采用上一个的策略
                    val[i][j] = val[i - 1][j];
                } else {
                    //对该函数的说明   val[i-1][j-hight[i]] 第i个商品的剩余容量
                    val[i][j] = Math.max(val[i - 1][j], value[i - 1] + val[i - 1][j - hight[i - 1]]);
                    //value[i] 是必定能取到的  后一个[j-hight[i]]剩余的空间,后一个的描述是,只有
                    //[j-hight[i]]空间 遍历到val[i]种类型的选择策略
                    //商品的类型是不断增加的
                    //原来函数的标准式:val[i][j] =  Math.max(val[i-1][j] , value[i] + val[i-1][j-hight[i]])
                }
            }
        }
        //遍历
        for (int i = 0; i < val.length; i++) {
            for (int i1 = 0; i1 < val[0].length; i1++) {
                System.out.print(Integer.toString(val[i][i1]) + " ");
            }
            System.out.println();
        }
    }
}

一个例题:关于动态规划和递归法

public class ClimbStairs {
    /**
     * Created with IntelliJ IDEA.
     * Description:
     * User: tongyongtao
     * Date: 2020-10-11
     * Time: 20:27
     * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
     * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
     * f(x)=f(x−1)+f(x−2)
     * 动态规划和递归法的区别: 自下而上 自上而下
     * 注意滚动数组的应用
     */
    public static void main(String[] args) {
        climbStairs(12);
        System.out.println(climbStairs1(12));
        System.out.println(climbStairs2(12));
        System.out.println(climbStairs3(12));
    }

    //滚动数组方法
    public static void climbStairs(int n) {
        //f(0)=1
        int p = 0;
        int q = 0;
        int r = 1;
        for (int i = 0; i < n; ++i) {
            p = q;
            q = r;
            r = p + q;
        }
        System.out.println(r);
    }

    //动态规划算法
    public static int climbStairs1(int n) {
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;

        for (int i = 2; i < dp.length; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];

    }

    //dp的优化
    public static int climbStairs2(int n) {
        int prev = 1;
        int cur = 1;
        for (int i = 2; i < n + 1; i++) {
            //tmp只是一个临时变量,用来存储cur的值,然后赋值给prev
            int tmp = cur;
            cur = prev + cur;
            prev = tmp;
        }
        return cur;


    }

    //递归
    public static int climbStairs3(int ints) {
        if (ints <= 2) {
            return ints;
        }
        return climbStairs3(ints - 1) + climbStairs3(ints - 2);
    }
}

一个例题:体会方程的构建

public class MaxSubArray {
    /*
     * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组
     * (子数组最少包含一个元素),返回其最大和
     *
     *
     * 思想:相加数组中的所有元素,直到遇到一个比这个和还要大的元素,舍弃这个和,重新求和,反复进行
     * */
    public static void main(String[] args) {
        int[] nums = new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4};
        maxSubArray1(nums);
        maxSubArray2(nums);
    }

    //f(i)=max{f(i−1)+a 转移方程 滚动思想

    public static void maxSubArray1(int[] ints) {
        //索引 0-ints.lenth
        //用来接收和
        if (ints.length==0){return;}
        int sum = 0;
        //最大的值
        int max = ints[0];
        for (int x : ints) {
            //转移方程,如果前面的和小于x,则舍弃前面的所有数
            sum = Math.max(sum + x, x);
            //比较与赋值
            max = Math.max(sum, max);
        }
        System.out.println(max);
    }

    //动态规划
    public static void maxSubArray2(int[] ints) {
        //数组的长度
        int length = ints.length;
        //构建一个dp存放以ints[i]为结尾最大子序
        int[] dp = new int[length];
        dp[0] = ints[0];
        for (int i = 1; i < length; i++) {
            // 取当前元素的值 和 当前元素的值加上一次结果的值中最大数
            dp[i] = Math.max(ints[i], dp[i - 1] + ints[i]);
        }
        //遍历dp数据获取最大的最大子序
        int max = 0;
        for (int x : dp) {
            max = Math.max(max, x);
        }
        System.out.println(max);
    }
}

背包问题的优化

public class DynamicProgramming1 {
    /**
     * Created with IntelliJ IDEA.
     * Description:
     * User: tongyongtao
     * Date: 2020-10-12
     * Time: 19:16
     * 重量:1 4 3
     * 价值:1500 3000 2000
     * 优化求出最后结果
     */
    public static void main(String[] args) {
        //存储每种商品的重量
        int[] weight = new int[]{1, 4, 3};
        //存储每种商品的价格
        int[] value = new int[]{1500, 3000, 2000};
        //背包的容量是4
        int n = 4;
        //构建一个二维数组用来表示每次选择的价值
        int[][] val = new int[weight.length + 1][n + 1];

        //初始化val[][0] val[0][];
        for (int i = 0; i < val.length; i++) {
            val[i][0] = 0;
        }
        for (int i = 0; i < val[0].length; i++) {
            val[0][i] = 0;

        }
        //由于第一行和第一列都进行的赋值,所以从1开始遍历
        //假设第i个商品的重量是大于本次的容量的则采取上一次的策略
        //如果是小于本次容量的则进行比较   //上一次的策略和本次可以容纳的策略
        //构建方程 max{val[i-1][j] , value[i] + val[i-1][j - weight[i]] }

        //建一个数组来记录信息
        int[][] path = new int[value.length + 1][n + 1];
        for (int i = 1; i < val.length; i++) {
            //容量每次递增
            for (int j = 1; j < val[0].length; j++) {
                //本次商品种类的重量是大于本次的容量的,选择的策略是上一次的
                //此处索引从1开始的
                if (weight[i - 1] > j) {
                    val[i][j] = val[i - 1][j];
                }
                  /* else {
                        //是可以采用本次商品的,策略是与上一次进行比较
                       val[i][j] = Math.max(val[i-1][j] , value[i-1] +val[i-1][j -weight[i-1]] );
                   }*/
                else if (val[i - 1][j] < value[i - 1] + val[i - 1][j - weight[i - 1]]) {
                    val[i][j] = value[i - 1] + val[i - 1][j - weight[i - 1]];
                    path[i][j] = 1;
                } else {
                    val[i][j] = 1;
                }
            }
        }

        for (int i = 0; i < val.length; i++) {
            for (int j = 0; j < val[0].length; j++) {
                System.out.print(val[i][j]);
            }
            System.out.println();
        }

        //从上往下遍历获取最后一次的背包存储情况
        int i = path.length - 1;
        int j = path[0].length - 1;
        while (i > 0 && j > 0) {
            if (path[i][j] == 1) {
                //索引从一开始
                System.out.printf("%d放入背包", i);
                //背包的容量被占据
                j -= weight[i - 1];

            }
            i--;
        }

    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352