解决动态规划问题4步曲

概述

  1. (确定状态)确定问题状态
    • 提炼最后一步
    • 子问题转化
  2. (求得方程)转移方程,把问题方程化
  3. (设初置界)按照实际逻辑设置初始条件和边界情况
  4. (确序再解)确定计算顺序并求解

一个案例:最少硬币组合

你打算买一本27元的书,你现有三种硬币,分别面值2元,5元和7元,每种硬币都充足。请问如何用个数最少的硬币组合正好付清?

正常人第一反应思路:

最少硬币组合?

  • 优先使用大面值硬币 —— 7+7+7+5=26,不符合求解目标27元。
  • 换种组合 —— 7+7+7+2+2+2=27,总共用了6枚硬币正好27元。
  • 实际正确答案 —— 7+5+5+5+5=27,才用了5枚硬币。

所以这里贪心算法是并不适用。

题目中关键词“最少的”,这是用到“动态规划”的味道

解决动态规划问题4步

第一步,确定问题状态

动态规划问题求解需要先开一个数组,并确定数组的每个元素f[i]代表什么,这就是确定这个问题的状态。这类似于解数学题中,设定x,y,z代表什么。

A、确定状态首先提取“最后一步”

最优策略必定是K枚硬币a1, a2, …, aK面值加起来是27。

找出不影响最优策略的最后一个独立角色,这道问题中,那枚最后的硬币aK就是最后一步。把aK提取出来,硬币aK之前的所有硬币面值加总是27-aK。因为总体求最硬币数量最少策略,所以拼出27-aK的硬币数也一定最少(重要设定)。

在这里插入图片描述

B、转化子问题

最后一步aK提出来之后,我们只要求出“最少用多少枚硬币可以拼出27- aK”就可以了。

这种与原问题内核一致,但是规模变小的问题,叫做子问题

为简化定义,我们设状态f(X)=最少用多少枚硬币拼出总面值X

我们目前还不知道最后的硬币aK面额多少,但它的面额一定只可能是{2, 5, 7}之一。

  • 如果aK是2,f(27)应该是f(27-2) + 1(加上最后这一枚面值2的硬币)
  • 如果aK是5,f(27)应该是f(27-5) + 1(加上最后这一枚面值5的硬币)
  • 如果aK是7,f(27)应该是f(27-7) + 1(加上最后这一枚面值7的硬币)

除此以外,没有其他的可能了。至此,通过找到原问题最后一步,并将其转化为子问题。

为求面值总额27的最小的硬币组合数的状态就形成了,用以下函数表示:

f(27) = min{f(27-2)+1, f(27-5)+1, f(27-7)+1}

在这里插入图片描述

第二步,转移方程,把问题方程化

f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}

动态规划都是要开数组,所以上面式子改用方括号表示。实际求解动态规划类问题,正确列出转移方程正确基本上就解决一半了。

递归的解法:

// f(X)返回最少用多少枚硬币拼出X
int f(int X) {// 0元钱只要0枚硬币if (X == 0) return 0;// 初始化用无穷大(int res = Integer.MAX_VALUE;// 最后一枚硬币是2元if (X >= 2) {res = Math.min(f(X – 2) + 1, res);}// 最后一枚硬币是5元if (X >= 5) {res =  Math.min(f(X – 5) + 1, res);}// 最后一枚硬币是7元if (X >= 7) {      res =  Math.min(f(X – 7) + 1, res);}return res;
}

执行图如下:

在这里插入图片描述

要算f(27),就要递归f(25)、f(22)、f(20),然后下边依次递归。

在这里插入图片描述

问题明显:重复递归太多

这是求f(27),等待时间还可以接受。如果求f(100)呢?

求总体最值,可优先考虑动态规划,不要贸然去递归。

第三步,按照实际逻辑设置边界情况和初始条件。

如果不按照实际逻辑设置边界情况和初始条件,即使转移方程正确也大概率无法跑通代码。

f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}的边界情况是[x-2][x-5][x-7]不能小于0(硬币面值为正),也不能高于27。

故对边界情况设定如下

如果硬币面值不能组合出Y,就定义f[Y]=正无穷。例如,f[-1] = f[-2] = … = 正无穷f[1] = min{f[-1]+1, f[-4]+1,f[-6]+1} = 正无穷特殊情况:本题的F[0]对应的情况为F[-2]、F[-5]、F[-7],按照上文的边界情况设定结果是正无穷,但是实际上F[0]的结果是存在的(即使用0个硬币的情况下),F[0]=0

可是按照我们刚刚的设定,F[0]=F[0-2]+1= F[-2]+1=正无穷岂不是矛盾?这种用转移方程无法计算,但是又实际存在的情况,就必须通过手动定义。这里手动强制定义初始条件为:F[0]=0

而从0之后的数值是没矛盾的,比如F[1]= F[1-2]+1= F[-1]+1=正无穷(正无穷加任何数结果还是正无穷),F[2] = F[2-2]+1 = F[0]+1=1

第四步,确定计算顺序并计算求解

那么开始计算时,是从F[1]F[2]开始呢?还是从F[27]F[26]开始呢?

判断计算顺序正确与否的原则是:当我们要计算F[X](等式左边,如F[10])的时候,等式右边(f[X-2]f[X-5]f[X-7]等)都是已经得到结果的状态,这个计算顺序就是OK的。

实际就是从小到大的计算方式(偶有例外的情况)。

例如我们算到F[12]的时候,发现F[11]F[10]F[9]都已经算过了,这种算法就是对的。而开始算F[27]的时候,发现F[26]还没有算,这样的顺序就是错的。

很显然这样的情况下写一个for循环就够了。

回到这道题,采用动态规划的算法,每一步只尝试三种硬币,一共进行了27步。算法时间复杂度(即需要进行的步数)为27*3。

与递归相比,没有任何重复计算

本文的题目来源:LeetCode - Medium - 322. Coin Change

代码如下:

public class CoinChange {public int coinChange(int[] coins, int amount) {int[] f = new int[amount + 1];Arrays.fill(f, Integer.MAX_VALUE);f[0] = 0;for (int i = 1; i <= amount; i++) {//如果通过放这个硬币能够达到数量ifor(int coin : coins) {if (i >= coin && f[i - coin] != Integer.MAX_VALUE)// 获得i的数量的硬币数就可能是获得i-A[j]重量硬币数的方案+1// 拿这个方案数量与原本的方案数打擂台,取最小值就行f[i] = Math.min(f[i - coin] + 1, f[i]);}}if (f[amount] == Integer.MAX_VALUE) {return -1;}return f[amount];}
}

总结

  1. 这是求最值问题,用动态规划方式求解。(案例:最少硬币组合)
  2. 进入求解过程,先确定问题状态
    • 提炼最后一步(最优策略中使用的最后一枚硬币aK
    • 子问题转化(最少的硬币拼出更小的面值X-aK
  3. 构建转移方程(f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}
  4. 设置初始条件和边界情况(f[0] = 0, 如果不能拼出Y,f[Y]=正无穷
  5. 确定计算顺序并计算求解(f[0], f[1], f[2],…)

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

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

相关文章

查看oracle监听服务器,处理Oracle 监听文件listener.log问题

如果连接时候变得较慢 查看Oracle日志记录&#xff0c;可能是因为此文件太大&#xff0c;超过2G&#xff0c;需要定期清理&#xff0c;(如果多用户&#xff0c;记得用root&#xff0c;可能没权限)查看listener.log&#xff1f;find / -name listener.log经查看&#xff0c;竟然…

美国oracle球场,美国体育馆考察——美国体育产业是如何盈利的?

体育是美国一项较高利润的产业&#xff0c;其发展规模、发展水平和效益都是世界一流的。美国体育馆考察&#xff0c;主要考察美国体育产业的盈利模式和体育赛事的赞助模式以及球馆的运营管理&#xff0c;并对比中美体育产业的差异&#xff0c;从中获得先进的体育产业运营思维&a…

php集成环境怎么打开,PHP集成开发环境PhpStorm快速入门指南(二):打开一个项目...

PhpStorm是一个轻量级且便捷的PHP IDE&#xff0c;其旨在提高用户效率&#xff0c;可深刻理解用户的编码&#xff0c;提供智能代码补全&#xff0c;快速导航以及即时错误检查。可随时帮助用户对其编码进行调整&#xff0c;运行单元测试或者提供可视化debug功能。PhpStorm 2019.…

计算机分php,计算机按照处理数据的形态分类,可以分为什么?

计算机按照处理数据的形态分类&#xff0c;可以分为&#xff1a;1、数字计算机&#xff0c;是以数字形式的量值在机器内部进行运算和存储的电子计算机&#xff1b;2、模拟计算机&#xff0c;是根据相似原理&#xff0c;用一种连续变化的模拟量作为被运算的对象的计算机&#xf…

2.oracle物理结构,oracle实验2oracle物理结构管理

oracle实验2oracle物理结构管理 (6页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;9.9 积分实验2 oracle物理存储结构管理、实验目的1. 掌握物理结构的创建和修改方法2. 掌握表空间的存储参数设置方…

linux mount 查看挂载目录,Linux下使用mount来挂载设备到目录

一般情况下直接mount 设备路径 目录路径&#xff0c;就可以了。umount 设备名&#xff0c;就可以卸载这个设备了使用lsblk -f可以查看挂载的设备&#xff0c;以及这些设备的文件系统。roottao-PC:/boot# lsblk -fNAME FSTYPE LABEL UUID MOUNTPOINTsda├─sda1├─sda2 vfat SY…

linux6.0 安装教程,CentOS 6.0安装步骤

1&#xff0e;安装引导选择安装或升级现有系统(Install or upgrade an existing system)&#xff1a;这个选项是默认的。 选择此选项&#xff0c;安装到您的计算机使用CentOS的图形安装程序的系统。2.检测光盘介质可以选择skip跳过3.选择安装过程中的语言这里选择chinese中文简…

netflow流量分析工具 linux,Centos5/Linux安装Nfdump和Nfsen图形界面分析netflow数据

Nfdump是linux下netflow数据采集分析工具&#xff0c;Nfsen是基于nfdump是web界面工具&#xff0c;服务器需先安装web服务器和php环境。安装rrdtool及所需组件&#xff1a;yum install perl-rrdtool rrdtool rrdtool-devel rrdutils flex byacc安装所需perl模块&#xff1a;yum…

linux嵌入式平台测试,protobuf-c 在arm linux 嵌入式平台的使用 测试

关于什么是protobuf&#xff0c;网上搜搜一大堆&#xff0c;很多人用的都还是json&#xff0c;以为json是多种语言传输数据是万能的&#xff0c;看完了protobuf的实现&#xff0c;就明白了简单高效才是王道。1、首先写一个.proto扩展名的文件json.proto&#xff0c;内容格式如下…

linux版车机安装步骤,RedHat Linux 9.0的安装(详细图解安装过程)

RedHat Linux版本:" b, t) b) b# }, t# z- fC& S$ x0 }) GRedHat Linux是目前世界上使用最多的Linux操作系统。因为它具备最好的图形界面&#xff0c;无论是安装、配置还是使用都十分方便&#xff0c;而且运行稳定&#xff0c;因此不论是新手还是老玩家都对它有很高的…

简单了解linux,linux简单了解

今天主要了解下linuxlinux目录结构包含:/&#xff1a;代表根目录bin(binaries):存放二进制可执行文件sbin(super user binaries)&#xff1a;存放二进制可执行文件&#xff0c;只有root才能访问etc(etcetera)存放系统配置文件usr(unix shared resource)&#xff1a;用于存放共享…

二级c语言评分标准一样吗,计算机二级评分严格吗 步骤错了有分吗

计算机二级考试不是人工阅卷&#xff0c;是由计算机评分&#xff0c;所以是很严格的。计算机二级机器阅卷主要看的是最后的输出文件&#xff0c;如果步骤错了导致结果不正确的话&#xff0c;也是没有分的。计算机二级评分标准计算机二级考试是电脑自动评分的&#xff0c;即上机…

c语言a 寻路算法,JS/HTML5游戏常用算法之路径搜索算法 A*寻路算法完整实例

本文实例讲述了JS/HTML5游戏常用算法之路径搜索算法 A*寻路算法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;完整实例代码如下&#xff1a;A*寻路算法#stage {border: 1px solid lightgray;}window.onload function () {var stage document.querySelector(#stage…

在wsl下运行c语言,在Windows10通过WSL架设linux/gcc c语言学习环境

在Windows10通过WSL架设linux/gcc c语言学习环境零&#xff1a;简单介绍与先决条件中国一般的大学C课程中都使用很过时的编译器来进行教授——比如说什么visual studio 6.0啊&#xff0c;dev c啊。以笔者的眼界所看到的C语言教程中&#xff0c;大多都建议学习者在Linux环境下学…

android studio gradle 自动更新,android studio gradle 两种更新方法更新

又快一年没有使用AS了&#xff0c;正好要查看一个Android项目代码&#xff0c;干脆升级到新版试试看新变化&#xff0c;旧版本为3.1.2&#xff0c;目前最新版本为3.4.2&#xff0c;AS的升级是很简单的直接update等待即可.升级完了&#xff0c;打开GIT下载的项目&#xff0c;启动…

android 线性布局蒙层,Android开发 - 掌握ConstraintLayout(一)传统布局的问题

在传统的Android开发中&#xff0c;页面布局占用了我们很多的开发时间&#xff0c;而且面对复杂页面的时候&#xff0c;传统的一些布局会显得非常复杂&#xff0c;每种布局都有特定的应用场景&#xff0c;我们通常需要各种布局结合起来使用来实现复杂的页面。随着ConstraintLay…

android sdk 4.4.4,4.4.4 not in Android SDK manager

问题I need to do some testing with 4.4.4 and it isnt available in my Android SDK Manager?Any ideas on what Im doing wrong?回答1:There is no problem at you Android SDK Manager, you just have to download the API 19.The API 19 is used by all the KitKat devi…

android7.0提示定位,解决android7.0上某些PopuWindow显示位置不正确的问题

网上关于android系统7.0的popupwindow适配的解决方案&#xff0c;基本都是一样的&#xff0c;就是重写PopupWindow里面的方法但是如何进行重写&#xff0c;对于一个初次接触的人来说&#xff0c;是个很头疼的问题。一来是涉及到java基础&#xff0c;二来是涉及到popupwindow的源…

html文档定义层标记是,jsp练习题目201312

《JSP商务网站设计》复习综合题型一、单项选择题1. 关于分页显示&#xff0c;下列的叙述哪一项是不正确的&#xff1f;()A)只编制一个页面是不可能实现分页显示的B)采用一至三个页面都可以实现分页显示C)分页显示中&#xff0c;记录集不必在页面跳转后重新生成D)分页显示中页面…

html一个页面同时加载多个饼图,Html5饼图绘制实现统计图的方法

Html5提供了强大的绘图API&#xff0c;让我们能够使用javascript轻松绘制各种图形。本文将主要讲解使用HTML5绘制饼图(统计图)的方法。先看一下饼图效果&#xff1a;这个图是动态生成的&#xff0c;根据传入的比例参数(数组)&#xff0c;来动态绘制饼图。饼图的大小也是根据高度…