八十九、动态规划系列背包问题之完全背包
@Author:Runsen
@Date:2020/9/15
动态规划需要搞定三个系列:三个背包,零钱问题和股票问题。今天就开始干掉三个背包问题。
三个背包问题:01背包,多重背包,完全背包。上次搞定了01背包,那么继续学习完全背包。
我们有NNN种物品,物品iii的重量为w[i]w[i]w[i],价格为p[i]p[i]p[i]。我们假定所有物品的重量和价格都是非负的,背包所能承受的最大重量W,每种物品都有无限件可用,则该问题成为完全背包问题 。
题目来源:https://www.acwing.com/problem/content/description/3/
先上代码,和01背包问题的解法有略微的改动,区别在于遍历体积jjj时从逆序改为顺序,就只有这一个不同,在上一篇博客中有关于01背包问题的理解。
# 代码基本一样
n, v = map(int, input().split())
goods = []
for i in range(n):goods.append([int(i) for i in input().split()])
dp = [0 for i in range(v+1)]
for i in range(n):for j in range(v+1): # 从前往后if j >= goods[i][0]:dp[j] = max(dp[j], dp[j-goods[i][0]]+goods[i][1])
print(dp[-1])# 测试代码
5 10
1 2
2 3
3 4
4 5
5 6
20
下面是有关完全背包的题目
Leetcode 279. 完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。示例 1:输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:输入: n = 13
输出: 2
解释: 13 = 4 + 9
首先,明确dp,然后找dp的转移方程。
这里,dp[i]:表示完全平方数和为i的 最小个数。这个是没有任何问题的,关键是dp的转移方程。
对于Runsen这个菜鸟来说,也很快指的这是转移方程,就是i减去k 加上1。本质上就是斐波那契数列的一个变形。
dp[i]=min(dp(i),dp[i−k]+1),k指的是平方和的数dp[i] = min(dp(i),dp[i-k] + 1) ,k 指的是平方和的数 dp[i]=min(dp(i),dp[i−k]+1),k指的是平方和的数
问题就转为了求n的最大平方和的序列。
i = 1
nums = []
while i*i <= n:nums.append(i*i)i = i + 1
然后就是完全背包的反例的问题了。那么这个动态规划的问题基本解决了。
n = int(input())
i = 1
nums = []
while i*i <= n:nums.append(i*i)i = i + 1
print(nums)
# dp = [0] * (n+1) 是求最大值,[float('inf')] * (n+1)求最小值
# 如果写成 dp = [0] * (n+1) ,那么永远0最小
dp = [float('inf')] * (n+1)
dp[0] = 0
for i in range(1,n+1):# j 是平方数for j in nums:if i<j:breakdp[i] = min(dp[i], dp[i - j] + 1)
print(dp[-1])
下面代码来源官方的动态规划,和Runsen的基本一样。
import math
def numSquares(n):""":type n: int:rtype: int"""square_nums = [i ** 2 for i in range(0, int(math.sqrt(n)) + 1)]dp = [float('inf')] * (n + 1)# bottom casedp[0] = 0for i in range(1, n + 1):for square in square_nums:if i < square:breakdp[i] = min(dp[i], dp[i - square] + 1)return dp[-1]
顺便补充一下:四平方定理: 任何一个正整数都可以表示成不超过四个整数的平方之和。 推论:满足四数平方和定理的数n(四个整数的情况),必定满足n=4a(8b+7)n=4^a(8b+7)n=4a(8b+7)
这个自己是不知道的,大家想深入:https://leetcode-cn.com/problems/perfect-squares/solution/wan-quan-ping-fang-shu-by-leetcode/
下面是四平方定理的代码
def numSquares(self, n):""":type n: int:rtype: int"""while n % 4 == 0: n /= 4 if n % 8 == 7: return 4 a = 0 while a**2 <= n: b = int((n - a**2)**0.5) if a**2 + b**2 == n: return (not not a) + (not not b) a += 1 return 3
Leetcode 300 最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
对于Runsen这个菜鸟来说,关键还是怎么找出dp和转移方程,dp[i]
是第i
个最长上升子序列。那么
dp[i]=max(dp[i],dp[k]+1)其中0<k<i−1dp[i] = max(dp[i], dp[k] + 1) 其中 0<k<i-1dp[i]=max(dp[i],dp[k]+1)其中0<k<i−1
class Solution:def lengthOfLIS(self, nums: List[int]) -> int:# 如果定义dp dp[i] 最长上升子序列 那么 dp[i] = max(dp[i], dp[k] + 1) 0<k<i-1m = len(nums)if m <= 1:return mdp = [ 1 for _ in range(m)]for i in range(1,m):for j in range(i):if nums[i] > nums[j]:dp[i] = max(dp[i], dp[j]+ 1 ) return max(dp)
Leetcode 322 零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
零钱兑换实际上就是完全背包的题目,也可以看作下楼梯的问题的变种
class Solution:def coinChange(self, coins: List[int], amount: int) -> int:# 第一步:定义dp数组或变量,首先明确题目说每种硬币的数量是无限的,但是会给定一个固定的 amount 金额,我们需要用最少的硬币数凑出这个金额,如果是01背包问题就是[0]开始;# 因此这个是一个完全背包的题目,还是下楼梯的问题的变种。完全背包求最小,那么初始就要时最大dp = [float('inf')] * (amount + 1)# 计算的起点 0 块钱当然是 0dp[0] = 0# 状态转移方程: f(11) = min(f(10),f(9),f(6)) + 1 for i in range(amount + 1):for j in coins:if i-j >=0 :dp[i] = min(dp[i],dp[i-j] + 1 )if dp[amount] > amount:# 如果dp[amount] 是amount + 1 ,说明了没有匹配的方式return -1return dp[-1]
至此完全背包就到这里结束了,完全背包注意dp的定义,求最大还是最小,完全背包的关键词就次数是无限的
八十九、动态规划系列背包问题之完全背包相关推荐
- 九十一、动态规划系列 背包问题之混合背包
@Author:Runsen @Date:2020/09/27 背包系列,是动态规划里一类典型的问题,主要有:01背包,完全背包,多重背包,混合背包,二维费用背包,分组背包,有依赖背包和泛化物品等.也 ...
- 九十、动态规划系列背包问题之多重背包
@Author:Runsen 曾几何时,才记得自己还是大一军训的菜鸟,带着 迷茫和憧憬踏入大学,踏入化工学院,却踏入这个行业,殊不知岁月是最高明的小偷,偷走时间,带走青春,一点线索也不留.大学的玩命学 ...
- 八十九、Python的GUI系列 | 使用PyQt5 快速构建一个GUI 应用
@Author:Runsen @Date:2020/7/11 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...
- 第三百八十九节,Django+Xadmin打造上线标准的在线教育平台—列表筛选结合分页...
第三百八十九节,Django+Xadmin打造上线标准的在线教育平台-列表筛选结合分页 根据用户的筛选条件来结合分页 实现原理就是,当用户点击一个筛选条件时,通过get请求方式传参将筛选的id或者值, ...
- JavaScript学习(八十九)—数组练习题
JavaScript学习(八十九)-数组练习题
- 耶鲁大学公开课博弈论(十八-十九)—— 信息集与最优子博弈
耶鲁大学公开课博弈论(十八-十九)-- 信息集与最优子博弈 理论与概念 在十八讲中介绍了全局纳什均衡点的相关内容,主要就是通过引入信息集的概念将传统的同时博弈也转变为序贯博弈问题,从而使用逆向推理解决 ...
- PCL点云处理之基于八叉树的三种邻近点搜索接口详细解释(八十九)
提示:体素内邻近点搜索,K个邻近点搜索,R半径邻域点搜索 ,是基于八叉树的三种点云邻近关系搜索方法,具体使用哪种要看具体的应用场景选择合适的 PCL点云处理之八叉树的三种邻近点搜索方法(八十九) 前言 ...
- DockOne微信分享( 八十九):恒生金融交易系统的Docker化实践
本文讲的是DockOne微信分享( 八十九):恒生金融交易系统的Docker化实践[编者的话]Docker可以显著改善企业软件研发流程.提升企业DevOps效率.借助Docker,企业可以对现有IT系 ...
- Android开发笔记(八十九)单例模式
基本概念 单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,从而方便对实例个数的控制并节约系统资源. 单例模式有三个特点: 1.某个类只能有一个实例: 2.它要自行创建这个实例: 3.它只有 ...
最新文章
- 使用appium做自动化测试时,send_keyss只能输入字母数字,无法输入中文
- 转 ios 里如何判断当前应用的定位服务是否可用
- shell无上传cmd等exe文件权限解决办法
- Ubuntu 下最简明的翻译词典(调用GoogleAPI,运行在终端)
- 单例模式——懒汉模式(C++)
- 技术需求趋势报告:移动、社会化、电子商务最热
- C语言课后习题(15)
- php可逆加密函数,简洁的PHP可逆加密函数
- 常见ActiveX控件下载大全
- VBA实现EXCEL随机本地随机刷题
- 加拿大布兰登大学计算机专业,名校大揭底:布兰登大学到底怎么样?
- WebDriver - 设置浏览器启动语言
- c++win32项目 如何显示后再删除一个绘图_以weblogic为中间件,部署一个项目,需如何做?...
- Linux 桌面玩家指南:03. 针对 Gnome 3 的 Linux 桌面进行美化
- Unity技能系统架构
- C# QRCode自定义二维码大小
- 【转载】按键精灵对安卓APP进行自动化界面点击测试
- 自定义my_strcpy与库strcpy【模拟实现字符串相关函数】
- 如何安装 IntelliJ IDEA 最新版本——详细教程
- Windows 7环境下ZTE U880 通过PC无线网卡共享上网的详细设置
热门文章
- c语言实现连续几个bit位置1,【C语言简单说】四:常量
- java全面的计算器代码_Java实现计算器的代码
- 全志 移除屏幕超时选项 Patch
- 计算机专业c语言题库,计算机专业C语言考试题.doc
- android qq分组展开,Android仿qq分组管理的第三方库
- python全排列字典序输出 递归_全排列-字典序列、递归方法c语言实现
- db2去除字段内容空格_Vue CLI3.x 配置指南生产环境去除console
- 工具类--日期工具类
- Python有了concurrent的话mutiprocessing和threading还有存在的意义吗?
- python配置日志的几种方式