dp动态规划详解下

news2024/12/27 18:54:55

dp动态规划详解上:https://blog.csdn.net/weixin_73936404/article/details/131527247?spm=1001.2014.3001.5501

目录

dp动态规划详解上:https://blog.csdn.net/weixin_73936404/article/details/131527247?spm=1001.2014.3001.5501

【案例1】

【题目描述】

【暴力递归  代码展示】

【展示如何改为动态规划】

【思路解析】

【代码实现】   通过对数器验证,代码正确

【案例2】

【题目描述】

【暴力递归 代码实现】

【动态规划 代码实现】

【案例3】//经过对数器校验,代码正确

【题目描述】

【暴力递归 代码实现】

【动态规划 代码实现】

【案例4】

【题目描述】

【暴力递归 代码实现】

【动态规划 代码实现 未优化版本】

【动态规划 优化版本】 斜率优化,如果有枚举这种策略,就可以使用这种优化策略。


【案例1】

【题目描述】

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

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

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

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

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

请返回最后获胜者的分数

【这道题暴力递归思路详见: https://blog.csdn.net/weixin_73936404/article/details/131162695?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22131162695%22%2C%22source%22%3A%22weixin_73936404%22%7D】

【暴力递归  代码展示】

/**
 * @ProjectName: study3
 * @FileName: Win
 * @author:HWJ
 * @Data: 2023/6/12 12:38
 */
public class Win {
    public static void main(String[] args) {
        int[] arr = {1,2,100,4};
        System.out.println(win(arr));
    }
    public static int win(int[] arr){
        if (arr == null || arr.length == 0){
            return 0;
        }
        return Math.max(f(arr, 0, arr.length-1), s(arr, 0, arr.length-1));
    }

    public static int f (int[] arr, int l, int r){
        if (l == r){ // 如果是最后一张排,因为是先手,就可以拿到这张牌,返回这张牌
            return arr[l];
        }
        return Math.max(arr[l] + s(arr, l+1, r), arr[r] + s(arr, l, r-1));
    }

    public static int s (int[] arr, int l, int r){
        if (l == r){ // 如果是最后一张排,因为是后手,就无法拿到这张牌,返回0
            return 0;
        }
        // 返回对手已经拿了一张牌
        // 此时我们便变为后手,
        // 因为对面先手,一定会拿对自己有利的牌,我们就无法拿到有利的牌,所以我们只能拿到最小的牌中对自己有利的牌
        return Math.min(f(arr, l+1, r), f(arr, l, r-1));
    }
}

【展示如何改为动态规划】

【思路解析】

因为这是一个两个递归函数,所有我们需要构建两个dp数组,根据暴力递归我们知道,他们是通过函数互相调用来求解最大值的过程,所有两个数组要互相依靠才能填充数组。

每个数组根据basecase 把可以填充的数据填充完。数组大小是由可变参数的变化范围决定的。

例如:一个正数数组    3   100   4   50

则他们需要两个4*4的数组。且i<j  所以数组对角线以下的数据是无用数据不需要填充,对角线数据是basecase,所以可以直接填充,其余数据根据递归的调用关系进行填充。

【代码实现】   通过对数器验证,代码正确

/**
 * @ProjectName: study3
 * @FileName: WinDp
 * @author:HWJ
 * @Data: 2023/7/5 10:47
 */
public class WinDp {
    public static void main(String[] args) {
        int[] arr = {1,2,100,4};
        System.out.println(getWin(arr));
    }

    public static int getWin(int[] arr) {
        final int N = arr.length;
        int[][] f = new int[N][N];
        int[][] s = new int[N][N];
        for (int i = 0; i < N; i++) { // 根据baseCase填充数组
            f[i][i] = arr[i];
            s[i][i] = 0;
        }

        for (int i = 1; i < arr.length; i++) {
            for (int j = 0; j < arr.length - i; j++) {
                // 这里就是讲递归填充  拆为数组填充
                f[j][j + i] = Math.max(arr[j] + s[j + 1][j + i], arr[j + i] + s[j][j + i - 1]);
                s[j][j + i] = Math.min(f[j + 1][j + i], f[j][j + i - 1]);
            }
        }
        return Math.max(f[0][N - 1], s[0][N - 1]);
    }

   


}

【案例2】

【题目描述】

描述:假设把整个棋盘放入第一象限,棋盘的最左下角是(0,0)位置,整个棋盘就是横坐标上9条线,纵坐标上10条线的区域,给出三个参数x,y,k;返回“马”从(0,0)位置出发,必须走K步,最终落在(x,y)上的方法数有多少种?

比如:K = 10;x = 7;y = 7  ,返回多少种方法? (中国象棋棋盘 10行9列)

【暴力递归 代码实现】

因为马的路线是可逆的,则从(0,0)走到(x,y)可以看作是(x,y)走到(0,0)

/**
 * @ProjectName: study3
 * @FileName: maxWays
 * @author:HWJ
 * @Data: 2023/7/5 11:45
 */
public class maxWays {
    public static void main(String[] args) {


    }

    public static int getMax(int x, int y, int k) {
        return ways(x, y, k);
    }

    public static int ways(int x, int y, int step) {
        if (x < 0 || x > 8 || y < 0 || y > 9) { // 如果马跳出棋盘了,返回0
            return 0;
        }
        if (step == 0) { // 如果已经步数为0了,如果跳到了(0,0)点则是一个有效路径
            return (x == 0 && y == 0) ? 1 : 0;
        }
        // 从源头不断往前回溯
        return ways(x + 2, y - 1, step - 1) +
                ways(x + 2, y + 1, step - 1) +
                ways(x + 1, y + 2, step - 1) +
                ways(x - 1, y + 2, step - 1) +
                ways(x - 2, y + 1, step - 1) +
                ways(x - 2, y - 1, step - 1) +
                ways(x + 1, y - 2, step - 1) +
                ways(x - 1, y + 2, step - 1);
    }
}

【动态规划 代码实现】

/**
 * @ProjectName: study3
 * @FileName: maxWays
 * @author:HWJ
 * @Data: 2023/7/5 11:45
 */
public class maxWays {
    public static void main(String[] args) {


    }

    public static int dpWays(int x, int y, int k) {
        int[][][] dp = new int[9][10][k + 1];
        dp[0][0][0] = 1;
        for (int i = 1; i < k + 1; i++) {
            for (int j = 0; j < 9; j++) {
                for (int l = 0; l < 10; l++) {
                    dp[j][l][i] += getValue(dp, j - 2, l + 1, i - 1);
                    dp[j][l][i] += getValue(dp, j - 2, l - 1, i - 1);
                    dp[j][l][i] += getValue(dp, j + 2, l + 1, i - 1);
                    dp[j][l][i] += getValue(dp, j + 2, l - 1, i - 1);
                    dp[j][l][i] += getValue(dp, j - 1, l + 2, i - 1);
                    dp[j][l][i] += getValue(dp, j + 1, l + 2, i - 1);
                    dp[j][l][i] += getValue(dp, j - 1, l - 2, i - 1);
                    dp[j][l][i] += getValue(dp, j + 1, l - 2, i - 1);
                }
            }
        }
        return dp[x][y][k];
    }

    public static int getValue(int[][][] dp, int x, int y, int z) {
        if (x < 0 || x > 8 || y < 0 || y > 9) {
            return 0;
        }
        return dp[x][y][z];
    }

}

【案例3】//经过对数器校验,代码正确

【题目描述】

给出五个参数,m,n,a,b,k;   m和n代表安全区的规格,a和b代表Bob当前所在位置, a和b可能一开始就不在安全区域,只要某一步不在安全区域就算死亡,k代表一定要走k步,它可以随机向上下左右任意一个方向走一步,计算他走k步后的生还可能性。所以如果他一开始就不在安全区域,那么他的生还几率一定为0

【暴力递归 代码实现】

/**
 * @ProjectName: study3
 * @FileName: BobWays
 * @author:HWJ
 * @Data: 2023/7/5 12:46
 */
public class BobWays {
    public static void main(String[] args) {
    }

    public static String probability(int n, int m, int i, int j, int k) {
        long all = (long) Math.pow(4, k);
        long live = process(n, m, i, j, k);
        long gcd = gcd(all, live);
        return String.valueOf((live/gcd) + "/" + (all/gcd));
    }

    public static long process(int n, int m, int i, int j, int step) {
        // 一旦越界就判定死亡
        if (i < 0 || i >= n || j < 0 || j >= m) {
            return 0;
        }
        //如果已经走完 且没有越界则 找到一种生还的可能
        if (step == 0) {
            return 1;
        }

        // 所有活下来的可能
        long live = process(n, m, i - 1, j, step - 1);
        live += process(n, m, i + 1, j, step - 1);
        live += process(n, m, i, j + 1, step - 1);
        live += process(n, m, i, j - 1, step - 1);
        return live;
    }

    public static long gcd(long a, long b){  // 求最大公约数
        return b == 0?a:gcd(b,a%b);
    }
 
}

【动态规划 代码实现】

/**
 * @ProjectName: study3
 * @FileName: BobWays
 * @author:HWJ
 * @Data: 2023/7/5 12:46
 */
public class BobWays {
    public static void main(String[] args) {
    }

    public static String dpProb(int n, int m, int i, int j, int k) {
        long all = (long) Math.pow(4, k);
        long[][][] dp = new long[n][m][k + 1];
        for (int l = 0; l < n; l++) {
            for (int o = 0; o < m; o++) {
                dp[l][o][0] = 1;
            }
        }
        for (int l = 1; l <= k; l++) {
            for (int o = 0; o < n; o++) {
                for (int p = 0; p < m; p++) {
                    dp[o][p][l] += getValue(dp, n, m, o - 1, p, l - 1);
                    dp[o][p][l] += getValue(dp, n, m, o, p - 1, l - 1);
                    dp[o][p][l] += getValue(dp, n, m, o + 1, p, l - 1);
                    dp[o][p][l] += getValue(dp, n, m, o, p + 1, l - 1);
                }
            }
        }
        long live = 0;
        if (i > 0 && i < n && j > 0 && j < m) {
            live = dp[i][j][k];
        }
        long gcd = gcd(all, live);
        return String.valueOf((live / gcd) + "/" + (all / gcd));
    }

    //得到有效数据,越界就返回0
    public static long getValue(long[][][] dp, int n, int m, int i, int j, int k) {
        if (i < 0 || i >= n || j < 0 || j >= m) {
            return 0;
        }
        return dp[i][j][k];
    }

    public static long gcd(long a, long b) {  // 求最大公约数
        return b == 0 ? a : gcd(b, a % b);
    }

}

【案例4】

// 使用对数器校验代码, 代码正确

【题目描述】

给出一个正数数组,里面正数不重复,每一个数代表一种面值的纸币,有任意多张,然后给出一个数,我们使用这些纸币组成这个数有多少种方法。

【暴力递归 代码实现】

/**
 * @ProjectName: study3
 * @FileName: ChangeMoney
 * @author:HWJ
 * @Data: 2023/7/5 14:07
 */
public class ChangeMoney {
    public static void main(String[] args) {
        int[] arr = {3, 5, 10, 1};
        System.out.println(change(arr, 1000));
    }

    public static long change(int[] arr, int money) {
        return process(arr, 0, money);
    }

    // arr是一个正数数组,里面的数字不重复,你可以无限使用同一个面值的纸币,要求最终能找零money
    // 求出总方法
    public static long process(int[] arr, int index, int rest) {
        if (index == arr.length) {
            return rest == 0 ? 1 : 0;
        }
        long ways = 0;
        for (int i = 0; i * arr[index] <= rest; i++) {
            ways += process(arr, index + 1, rest - i * arr[index]);
        }
        return ways;
    }
}

【动态规划 代码实现 未优化版本】

/**
 * @ProjectName: study3
 * @FileName: ChangeMoney
 * @author:HWJ
 * @Data: 2023/7/5 14:07
 */
public class ChangeMoney {
    public static void main(String[] args) {
        
    }

    public static long change2(int[] arr, int money) {
        int N = arr.length;
        long[][] dp = new long[N + 1][money + 1];
        dp[N][0] = 1;
        for (int index = N - 1; index >= 0; index--) {
            for (int rest = 0; rest <= money; rest++) {
                long ways = 0;
                for (int i = 0; i * arr[index] <= rest; i++) {
                    ways += dp[index + 1][rest - i * arr[index]];
                }
                dp[index][rest] = ways;
            }
        }
        return dp[0][money];
    }

}

【动态规划 优化版本】 斜率优化,如果有枚举这种策略,就可以使用这种优化策略。

 可以利用同层信息加速

/**
 * @ProjectName: study3
 * @FileName: ChangeMoney
 * @author:HWJ
 * @Data: 2023/7/5 14:07
 */
public class ChangeMoney {
    public static void main(String[] args) {

    }

    public static long change3(int[] arr, int money) {
        int N = arr.length;
        long[][] dp = new long[N + 1][money + 1];
        dp[N][0] = 1;
        for (int index = N - 1; index >= 0; index--) {
            for (int rest = 0; rest <= money; rest++) {
                dp[index][rest] = dp[index-1][rest];
                if (rest - arr[index] >= 0){
                    dp[index][rest] += dp[index][rest - arr[index]];
                }
            }
        }
        return dp[0][money];
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

强度(极限强度、屈服强度)、韧性材料与脆性材料(韧性材料与脆性材料的强度、为什么脆性材料在压缩时比在拉伸时更坚固?)、材料的延展性、韧性、弹性

1.强度 强度&#xff08;Strength&#xff09;是材料可以承受的应力的量度&#xff0c;通常使用极限强度&#xff08;Ultimate strength&#xff09;和屈服强度&#xff08;Yield strength&#xff09;来定义材料的强度-极限。 材料的极限抗拉强度定义为在拉伸试验过程中达到的…

windows 编译libyuv

一、libyuv下载 git clone https://chromium.googlesource.com/external/libyuv 二、libjpeg-turbo下 git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git 三、编译可以参考 BUILDING.md 需要环境&#xff1a; VS2019 CMake YASM 启动vs工具 编译&#xff1…

js模块化开发

◼ 到底什么是模块化、模块化开发呢&#xff1f;  事实上模块化开发最终的目的是将程序划分成一个个小的结构&#xff1b;  这个结构中编写属于自己的逻辑代码&#xff0c;有自己的作用域&#xff0c;定义变量名词时不会影响到其他的结构&#xff1b;  这个结构可以将自己…

SAP S4 Hana 下面ACDOCA 凭证行字段增强创建过程

网上找到这个类下面是可以新增增强的 现在需要在如下位置建立四代增强点 保存以后会出现下面的增强项 保存激活后&#xff0c;完成在源程序中增加了一个4代显式增强点.上面步骤只是在程序中建立了一个增强点&#xff0c;并没有执行什么动作&#xff0c;就相当于建立一个容器。如…

Python将Excel数字对应列的字母写成字典(json)

在日常的办公中&#xff0c;我们经常需要利用python去读写Excel类型的文件&#xff0c;有时候我们需要将每个数字代表的列的字母表现出来&#xff0c;那么我们可以利用Python实现&#xff0c;而且今天的代码可以根据自己的需求去任意的改变你想规定的长度 如,或者更长 a {1:…

1分钟搭建VPN服务器

1分钟搭建一个VPN服务器 VPN技术在保障网络通信安全和隐私上发挥着重要作用。IPsec VPN是其中一种常用的VPN模式。本文将介绍如何通过使用Docker来快速搭建IPsec VPN Server。 什么是IPsec VPN&#xff1f; IPsec即Internet Protocol Security&#xff0c;是一种用于保护互联…

「2024」预备研究生mem- 形式逻辑强化:逻辑的特殊文字表述方式(重点记忆)

一、形式逻辑强化&#xff1a;逻辑的特殊文字表述方式 二、课后题

关于torch.load报出找不到模型的错误,但路径明明正确

后来发现是因为使用 torch.save(model,save.pt) 会保存整个文件时会默认保存训练py文件的父目录&#xff0c;用torch.load导入文件时搜索路径必须有此父路径&#xff0c;否则将会提示no model named model这样的错误 解决办法是使用sys.path.apend把该父目录加入搜索路径中 …

Java开发 - 探寻Spring的秘密

前言 Spring是企业级J2EE一站式解决方案&#xff0c;提供了整个项目的表现层、业务层、持久层&#xff0c;而且&#xff0c;它的生态特别完善&#xff0c;可以和其他框架无缝对接&#xff0c;现在做Java的哪个项目里没有Spring的说出不去都不信。但往往我们开发者只重视项目是…

重定向:电商行业打败对手的杀手锏

重定向是一种在线营销策略&#xff0c;针对对产品或服务表示兴趣的潜在客户。可以追踪那些访问过您的网站、但未进行过消费的用户&#xff0c;再次向他们展示相关产品&#xff0c;激起消费欲。再营销则是可以追踪那些将商品加入网页购物车&#xff0c;但最后没有购买的用户&…

物流RFID设备一般在哪些场景应用?

随着现代物流行业的快速发展&#xff0c;传统条码技术信息量少&#xff0c;易脏污损毁&#xff0c;耐用性不高等问题很难满足物流企业多样化的需求&#xff0c;物流RFID设备的应用也越来越广泛。下面我们就跟大家一起来分析一下&#xff0c;物流RFID设备可以在哪些场景中应用。…

计算机体系结构基础知识介绍之动态调度(三)

首先回顾一下tomasulo算法&#xff0c; Tomasulo算法的第一个优点是分布式的冒险检测逻辑&#xff0c;这是通过使用预留站和公共数据总线实现的。预留站是一种存储指令和操作数的缓冲区&#xff0c;每个功能单元都有自己的预留站。公共数据总线是一种广播结果的方式&#xff0…

SpringBoot07:Thymeleaf模板引擎

目录 一、Thymeleaf 1、模板引擎 2、引入Thymeleaf 3、Thymeleaf分析 二、测试 1、编写一个TestController 2、编写一个测试页面welcome.html放在templates目录下 3、启动项目请求测试 三、Thymeleaf语法学习 1、修改测试请求&#xff0c;增加数据传输 2、要使用thy…

zabbix服务部署

文章目录 zabbix1 zabbix简介1.1 组成部件1.2 监控原理1.3 Zabbix 6.0新特性1.4 Zabbix6.0功能组件1.4.1 Zabbix Server1.4.2 数据库1.4.3 Web界面1.4.4 Zabbix Agent1.4.5 Zabbix Proxy1.4.6 Java Gateway 2 部署zabbix服务端2.1 部署Nginx2.2 安装PHP2.3 修改Nginx配置2.4 修…

Docker安装ElasticSearch7.14.0 docker安装elasticsearch7.14.0完整详细教程

Docker安装ElasticSearch7.14 docker安装elasticsearch7.14完整详细教程 Docker 上安装 ElasticSearch 7.14.0 的步骤&#xff1a;选择要安装的ElasticSearch 版本1、拉取 ElasticSearch 镜像2、创建并运行容器关闭容器启动容器重启容器 3、elasticsearch常用端口以及作用4、测…

耳夹式骨传导耳机测评!2023年最全耳夹骨传导耳机盘点

现在市面上的骨传导耳机品牌层出不穷&#xff0c;骨传导耳机好不好用&#xff0c;主要还是看耳机的品牌背景以及独家的音质技术调配&#xff0c;较大的骨传导耳机品牌在购买时售后以及使用体验上都具有一定的保障&#xff0c;下面就分享一些值得入手的骨传导耳机给大家吧~ 第一…

安装.net framework3.5 无法打开运行空间池,服务器管理器winRM插件可能已经损坏

解决方案&#xff1a; 1.以管理员权限打开命令提示符&#xff0c;然后运行如下命令&#xff1a; "reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f" 2.然后运行"winrm quickco…

玩转 TypeScript 中【class类】的定义与使用方法解读。

目录 类的概念类的继承 &#xff1a;类的存取器&#xff1a;类的静态方法与静态属性&#xff1a;类的修饰符&#xff1a;参数属性&#xff1a;抽象类&#xff1a;类的类型: 类的概念 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JavaScript 中的类建立在原型上&a…

java.lang.NoSuchMethodError异常原因及解决办法

java.lang.NoSuchMethodError异常原因及解决办法 第一种简单的情况就是本类中需要调用的方法名称错误&#xff0c;这种情况就需要去检查方法名称是否正确&#xff0c;避免调用的方法和本类中的有相同的名称。 第二种情况就是jar包的问题 可能是jar包没有导入进来或者jar包导入…

HTTP第17讲——Cookie机制

Cookie的诞生背景 HTTP 是“无状态”的&#xff0c;这既是优点也是缺点。优点是服务器没有状态差异&#xff0c;可以很容易地组成集群&#xff0c;而缺点就是无法支持需要记录状态的事务操作。 后来发明的 Cookie 技术&#xff0c;给 HTTP 增加了“记忆能力”。 什么是Cookie…