第十九节:暴力递归到动态规划

一 动画规划的概念 优化出现重复解的递归

一旦写出递归来,改动态规划就很快

尝试策略和状态转移方程是一码事

学会尝试是攻克动态规划最本质的能力

如果你发现你有重复调用的过程,动态规划在算过一次之后把答案记下来,下回在越到重复调用过程就直接调

做题思路 一定要从尝试入手

动态规划的套路从尝试出发,从尝试递归出发,然后在改动态规划的时候第一步找到base的情况填上相应位置的数,然后根据下一步的条件推出其他位置的数;

二 给定四个参数 N、M、K、P,返回方法数,机器人必须走 K 步

2.1描述

假设有排成一行的N个位置,记为1~N,N 一定大于或等于 2

开始时机器人在其中的M位置上(M 一定是 1~N 中的一个)

如果机器人来到1位置,那么下一步只能往右来到2位置;

如果机器人来到N位置,那么下一步只能往左来到 N-1 位置;

如果机器人来到中间位置,那么下一步可以往左走或者往右走;

规定机器人必须走 K 步,最终能来到P位置(P也是1~N中的一个)的方法有多少种

给定四个参数 N、M、K、P,返回方法数。

2.2 分析

2.3 代码

// 机器人当前来到的位置是cur,
    // 机器人还有rest步需要去走,
    // 最终的目标是aim,
    // 有哪些位置?1~N
    // 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少?
    public static int process1(int cur, int rest, int aim, int N) {
        if (rest == 0) { // 如果已经不需要走了,走完了!
            return cur == aim ? 1 : 0;
        }
        // (cur, rest)
        if (cur == 1) { // 1 -> 2
            return process1(2, rest - 1, aim, N);
        }
        // (cur, rest)
        if (cur == N) { // N-1 <- N
            return process1(N - 1, rest - 1, aim, N);
        }
        // (cur, rest)
        return process1(cur - 1, rest - 1, aim, N) + process1(cur + 1, rest - 1, aim, N);
    }

2.4 优化 递归改动态规划 一 有重复解的递归是可以优化的

上面递归的过程中出现了重复的值,采用缓存法记录已经走过的路就不用再走了,一个字问题保证只算一次


public static int ways2(int N, int start, int aim, int K) {
        if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
            return -1;
        }
        int[][] dp = new int[N + 1][K + 1];
        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= K; j++) {
                dp[i][j] = -1;
            }
        }
        // dp就是缓存表
        // dp[cur][rest] == -1 -> process1(cur, rest)之前没算过!
        // dp[cur][rest] != -1 -> process1(cur, rest)之前算过!返回值,dp[cur][rest]
        // N+1 * K+1
        return process2(start, K, aim, N, dp);
    }

    // cur 范: 1 ~ N
    // rest 范:0 ~ K
    public static int process2(int cur, int rest, int aim, int N, int[][] dp) {
        if (dp[cur][rest] != -1) {
            return dp[cur][rest];
        }
        // 之前没算过!
        int ans = 0;
        if (rest == 0) {
            ans = cur == aim ? 1 : 0;
        } else if (cur == 1) {
            ans = process2(2, rest - 1, aim, N, dp);
        } else if (cur == N) {
            ans = process2(N - 1, rest - 1, aim, N, dp);
        } else {
            ans = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp);
        }
        dp[cur][rest] = ans;
        return ans;

    }

三 给定一个整型数组arr,代表数值不同的纸牌排成一条线

范围模型 玩家博弈问题

3.1 描述

给定一个整型数组arr,代表数值不同的纸牌排成一条线

玩家A和玩家B依次拿走每张纸牌

规定玩家A先拿,玩家B后拿

但是每个玩家每次只能拿走最左或最右的纸牌

玩家A和玩家B都绝顶聪明

请返回最后获胜者的分数。

3.2分析

先手

后手,后手能拿的只能是先手拿剩下的

优化1 傻缓存

优化二

3.3代码

package class18;

public class Code02_CardsInLine {

    // 根据规则,返回获胜者的分数
    public static int win1(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int first = f1(arr, 0, arr.length - 1);
        int second = g1(arr, 0, arr.length - 1);
        return Math.max(first, second);
    }

    // arr[L..R],先手获得的最好分数返回
    public static int f1(int[] arr, int L, int R) {
        if (L == R) {
            return arr[L];
        }
        int p1 = arr[L] + g1(arr, L + 1, R);
        int p2 = arr[R] + g1(arr, L, R - 1);
        return Math.max(p1, p2);
    }

    // // arr[L..R],这里面是对手做决定,后手获得的最好分数返回
    public static int g1(int[] arr, int L, int R) {
        if (L == R) {
            return 0;
        }
        int p1 = f1(arr, L + 1, R); // 对手拿走了L位置的数
        int p2 = f1(arr, L, R - 1); // 对手拿走了R位置的数
        return Math.min(p1, p2);
    }

    public static int win2(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int N = arr.length;
        int[][] fmap = new int[N][N];
        int[][] gmap = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                fmap[i][j] = -1;
                gmap[i][j] = -1;
            }
        }
        int first = f2(arr, 0, arr.length - 1, fmap, gmap);
        int second = g2(arr, 0, arr.length - 1, fmap, gmap);
        return Math.max(first, second);
    }

    // arr[L..R],先手获得的最好分数返回
    public static int f2(int[] arr, int L, int R, int[][] fmap, int[][] gmap) {
        if (fmap[L][R] != -1) {
            return fmap[L][R];
        }
        int ans = 0;
        if (L == R) {
            ans = arr[L];
        } else {
            int p1 = arr[L] + g2(arr, L + 1, R, fmap, gmap);
            int p2 = arr[R] + g2(arr, L, R - 1, fmap, gmap);
            ans = Math.max(p1, p2);
        }
        fmap[L][R] = ans;
        return ans;
    }

    // // arr[L..R],后手获得的最好分数返回
    public static int g2(int[] arr, int L, int R, int[][] fmap, int[][] gmap) {
        if (gmap[L][R] != -1) {
            return gmap[L][R];
        }
        int ans = 0;
        if (L != R) {
            int p1 = f2(arr, L + 1, R, fmap, gmap); // 对手拿走了L位置的数
            int p2 = f2(arr, L, R - 1, fmap, gmap); // 对手拿走了R位置的数
            ans = Math.min(p1, p2);
        }
        gmap[L][R] = ans;
        return ans;
    }

3.4 优化代码

 public static int win3(int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int N = arr.length;
        int[][] fmap = new int[N][N];
        int[][] gmap = new int[N][N];
        for (int i = 0; i < N; i++) {
            fmap[i][i] = arr[i];
        }
        for (int startCol = 1; startCol < N; startCol++) {
            int L = 0;
            int R = startCol;
            while (R < N) {
                fmap[L][R] = Math.max(arr[L] + gmap[L + 1][R], arr[R] + gmap[L][R - 1]);
                gmap[L][R] = Math.min(fmap[L + 1][R], fmap[L][R - 1]);
                L++;
                R++;
            }
        }
        return Math.max(fmap[0][N - 1], gmap[0][N - 1]);
    }

    public static void main(String[] args) {
        int[] arr = { 5, 7, 4, 5, 8, 1, 6, 0, 3, 4, 6, 1, 7 };
        System.out.println(win1(arr));
        System.out.println(win2(arr));
        System.out.println(win3(arr));

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/700101.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2-1基于matlab的拉普拉斯金字塔图像融合算法

基于matlab的拉普拉斯金字塔图像融合算法&#xff0c;可以使部分图像模糊的图片清楚&#xff0c;也可以使图像增强。程序已调通&#xff0c;可直接运行。 2-1 图像融合 拉普拉斯金字塔图像融合 - 小红书 (xiaohongshu.com)

Camtasia Studio2024破解神器下载,轻松上手视频剪辑

嘿&#xff01;今天我要和大家分享一个神奇的软件——Camtasia Studio2024最新版的破解安装包&#xff01;&#x1f3ac; 作为一个视频制作爱好者&#xff0c;我一直在寻找一款功能强大、易于操作的视频编辑软件。而Camtasia Studio2024就是我心目中的完美选择&#xff01;它不…

数值计算精度问题(浮点型和双整型累加精度测试)

这篇博客介绍双整型和浮点数累加精度问题,运动控制轨迹规划公式有大量对时间轴的周期累加过程,如果我们采用浮点数进行累加,势必会影响计算精度。速度的不同 进一步影响位置积分运算。轨迹规划相关问题请参考下面系列文章,这里不再赘述: 1、博途PLC 1200/1500PLC S型速度曲…

工业机器视觉系统如何实现精准检测?

机器视觉系统是指利用机器替代人眼做出各种测量和判断。一种比较复杂的系统。大多数系统监控对象都是运动物体&#xff0c;系统与运动物体的匹配和协调动作尤为重要&#xff0c;所以给系统各部分的动作时间和处理速度带来了严格的要求。在某些应用领域&#xff0c;例如机器人、…

网工使用频率最高的6款软件,都有的绝对是资深打工人

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 有不少朋友问到&#xff0c;深耕网络工程师需要哪些软件&#xff1f; 其实网工行业需要的软件还挺多的&…

外卖抢单神器

在现代快节奏的生活中&#xff0c;外卖服务已成为许多人日常生活的一部分&#xff0c;给外卖行业带来前所未有的机遇和挑战。随着市场竞争的加剧&#xff0c;许多外卖员开始寻求方法以提升接单效率。但在此过程中&#xff0c;道德和合规性是业务持续性的关键。 正直的经营不仅…

iOS ------ 对象的本质

一&#xff0c;OC对象本质&#xff0c;用clang编译main.m OC对象结构都是通过基础的C/C结构体实现的&#xff0c;我们通过创建OC文件及对象&#xff0c;将OC对象转化为C文件来探寻OC对象的本质。 代码&#xff1a; interface HTPerson : NSObject property(nonatomic,strong)…

axure9设置组件自适应浏览器大小

问题&#xff1a;预览时不展示下方的滚动条 方法一&#xff1a;转化为动态面板 1.在页面上创建一个矩形 2.右键-转化为动态面板 3.双击进入动态面板设置 4.设置动态面板矩形的颜色 5.删除原来的矩形 6.关闭动态面板&#xff0c;点击预览 7.此时可以发现底部没有滚动条了 方法…

面试题:如何避免索引失效?

(1) 范围条件查询 (2) 不要在索引上使用函数运算, 否则索引也会失效. 比如在索引上使用切割函数, 就会使索引失效. (3) 字符串不加引号, 造成索引失效. (4) 尽量使用索引覆盖, 避免 select *, 这样能提高查询效率. 如果索引列完全包含查询列, 那么查询的时候把要查的列写出来…

插入删除单链表指定结点-偷天换日法

王道说下面的代码有BUG&#xff0c;比如当删除的结点p在最后一个元素时&#xff0c;p->nextNULL; So *q NULL; q->data就是错误的&#xff0c;我认为加个判断就行 加个判断即可 /*看着是删除q了&#xff0c;从结果上看就是把p删除了 偷天换日法*/ bool DeleteNode(LNod…

【源码】二开版微盘交易系统/贵金属交易平台/微交易系统

二开版微盘交易系统/贵金属交易平台/微交易系统 一套二开前端UI得贵金属微交易系统&#xff0c;前端产品后台可任意更换 此系统框架不是以往的至尊的框架&#xff0c;系统完美运行&#xff0c;K线采用nodejs方式运行 K线结算都正常&#xff0c;附带教程 资源来源:https://www.…

小迪安全代码语言回溯

java安全 第一个就是文件上传&#xff0c;可以通过../上传到上一级目录&#xff0c;以及别的目录&#xff0c;避免本目录不可以执行 jw令牌窃取 令牌由三部分组成&#xff0c;以.号分割&#xff0c;在java的程序看到cookie是三个奇怪的字符串以.号分开&#xff0c;可以确定是…

matlab-2-simulink-小白教程-如何绘制电路图进行电路仿真

以上述电路图为例&#xff1a;包含D触发器&#xff0c;时钟CLK,与非门 一、启动simulink的三种方式 方式1 在MATLAB的命令行窗口输入“Simulink”命令。 方式2 在MATLAB主窗口的“主页”选项卡中&#xff0c;单击“SIMULINK”命令组中的Simulink命令按钮。 方式3 从MATLAB…

MySQL-----JOIN语句之内连接

在我们使用MySQL进行项目的开发过程中&#xff0c;仅仅对一张表进行操作是远远不够的&#xff0c;真正的应用中经常需要从多个数据表中读取数据。我们在使用的过程中&#xff0c;尝尝通过 SELECT, UPDATE 和 DELETE 语句配合使用 JOIN 来联合多表查询。 JOIN 分类 INNER JOIN…

【Text2SQL 论文】CHESS:利用上下文来合成 SQL 的 pipeline

文章目录 一、论文速读二、CHESS pipeline2.1 Entity and Context Retrieval2.2 Schema Selection2.3 Query Generation 三、预处理四、实验五、总结讨论 一、论文速读 本文提出了一个 pipeline 框架——CHESS——来解决应用于复杂的真实数据库场景下的 Text2SQL 问题。 在现…

AC/DC电源模块的原理、特点以及其在实际应用中的重要性

BOSHIDA AC/DC电源模块的原理、特点以及其在实际应用中的重要性 AC/DC电源模块是一种用于将交流电转换为直流电的设备&#xff0c;广泛应用于各种电子设备中。这种电源模块可以有效地将电力从电网中提取出来&#xff0c;并将其转换为稳定的直流电源&#xff0c;供给各种不同功…

有趣的数学 数值方法简述

数值方法简述 令许多纯数学家烦恼的是&#xff0c;并非所有问题都能通过解析方法解决&#xff0c;也就是说&#xff0c;不能通过使用已知规则和逻辑来获得精确解的方法。 这时就需要使用数值方法。 数值方法将近似解&#xff0c;或者在最坏的情况下&#xff0c;将解限制在某个范…

Sketch文件轻松转换为PSD的简便方法

由于Sketch只支持在Mac上使用&#xff0c;当设计师使用Sketch完成设计草案&#xff0c;需要与使用Windows的同事连接设计项目时&#xff0c;会遇到同事无法打开或在Photoshop中查看和编辑的情况&#xff0c;这真的很尴尬。别担心&#xff01;在本文中&#xff0c;我们将分享Ske…

笨蛋学算法之LeetCodeHot100_1_两数之和(Java)

package com.lsy.leetcodehot100;public class _Hot1_两数之和 {//自写方法public static int[] twoSum1(int[] nums, int target) {//定义存放返回变量的数组int[] arr new int[2];//遍历整个数组for (int i 0; i < nums.length; i) {//从第二个数开始相加判断for (int j…

mysql和redis的双写一致性问题

一&#xff0c;使用方案 在使用redis作为缓存的场景下&#xff0c;我们一般使用流程如下 二&#xff0c;更新数据场景 我们此时修改个某条数据&#xff0c;如何保证mysql数据库和redis缓存中的数据一致呢&#xff1f; 按照常规思路有四种办法&#xff0c;1.先更新mysql数据&a…