背包问题

0-1背包

匿名 (未验证) 提交于 2019-12-02 23:43:01
2019独角兽企业重金招聘Python工程师标准>>> 问题描述 : 给定n种物品和一背包,物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品(物品不能分割),使得装入背包中物品的总价值最大? 抽象描述: x[n]:表示物品的选择,x[i]=1表示选择放进物品i到背包中。 问题分析: 1.抽象之后背包问题转换为找到一个最优的数组,x1,x2,.....,xn的0-1序列。 2.假设最优解的序列为x1,x2,.....,xn,能使背包容量C的总价值最大. 如果,x1=1,则x2,...,xn是C-w1容量的背包的总价值 依然是 最大的序列; 如果,x1=0,则x2,....,xn是C容量的背包的总价值 依然是 最大的序列。 这就是我们所说的最优子结构性质。 3.进一步分析:我们用m(i,j)表示为已经判断好了i:n的序列的背包最大价值,并且此时的背包剩余的容量为j,对物品i进行判断 如果j>wi, 就只要做出选择wi和不选择wi情况下,哪种更能使背包的总价值更大:m(i,j)=max{ m(i+1,j),m(i+1,j-wi)+vi} (注意这是个递归式) 如果j<wi: m(i,j)=m(i+1,j) 初始化: m(n,j)=vn (j>= wn); m(n,j)=0 (0<=j< wn) m(0,C)=0 最终的结果:m(1,C) 4

关于满减优惠券叠加的背包算法

匿名 (未验证) 提交于 2019-12-02 23:42:01
昨天同事遇到一个优惠券使用的问题,用下班时间和早上研究了下,和动态规划的背包问题有关,但又不同于背包,感觉比较有意思就在这里做个记录,在群里讨论和梳理成文字也使自己更清晰的了解自己知道什么。 问题的精简描述为:购买商品时,有多张满减优惠券可用(可叠加使用),求最优策略(减免最多)。 准确描述为: 设共有n张优惠券C: [(V1, D1), (V2, D2), (V3, D3), ..., (Vn, Dn)],其中Vn为面值,Dn为减免值(对于一张优惠券Cx,满Vx减Dx),优惠券为单张,可叠加使用(使用过一张后,如果满足面值还可以使用其他优惠券)。求商品价值为M时,使用优惠券的最优策略:1.减免值最多,2.优惠券剩余最优(比如对于 C1 (2, 0.1) 、C2 (1, 0.1) 只能选择一张的最优取舍就是用C1留C2 )。 输入: 期望输出: 看到其他人推荐背包,由于没用过背包算法,通过 动态算法规划算法背包问题 学习了下背包的思想。顺便了解一下动态规划能解决什么问题: 适用动态规划方法求解的最优化问题应该具备的两个要素:最优子结构和子问题重叠。――《算法导论》动态规划原理 优惠券问题看起来和背包问题很像,但是有一点不同 图1 背包问题和优惠券问题的不同 图中,背包问题里面的数据为:在负重已知的前提下能装物品的最优总价值;优惠券问题里面的数据为总金额能使用优惠券的最优总减免值。

0-1背包回溯算法【适合小白,带分析+注释】

匿名 (未验证) 提交于 2019-12-02 23:34:01
0-1背包回溯算法【适合小白,带分析+注释】 题目:用回溯算法实现0-1背包,背包的容积为7 装4件物品,物品的价值分别9,10,7,4,物品的重量分别是3,5,2,1,请用回溯法实现背包所能装入的最大价值? 分析: 所谓0-1背包,为了最大的价值,考虑当前物品装或者不装【只有这两种情况,而背包问题可以只装物品的部分】,解空间可以用子集数来表示。 解0-1背包问题的回溯法,与装载问题的回溯法类似,搜索解空间树时,只要左孩子结点是一个可行结点,搜索就进入左子树,而只有在右子树包含更优解时才进入右子树,否则就把右子树剪掉。 这就是问题的关键,怎么把右子树剪掉:我们可以设计一个上界函数,只有当上界函数返回的值大于当前最优值,才进入右子树(也就是说,当前这个物品我不装,而去装下一个物品,得到的价值更大) 上界函数:将物品按单位重量价值降序排列,依次取物品装入【这是为了得到一个上界值,其实本身是不能取到的,所以当物品放不下,我们可以取部分装,这就类似背包问题】 所以物品的价值,重量,单位价值属性用结构体存储,本方法大部分处理时间在这个,其实回溯很简单,主要是为了oj提交,直接根据题目所给的数据进行编程,如果只是想练习回溯,可以自己事前计算好物品的单位重量价值,然后将价值数组,重量数组也按物品的单位重量价值降序排列 转载请标明出处: 0-1背包回溯算法【适合小白,带分析+注释】 文章来源:

背包九讲

匿名 (未验证) 提交于 2019-12-02 22:56:40
背包九讲 前言 本篇文章是我(dd_engi)正在进行中的一个雄心勃勃的写作计划的一部分,这个计划的内容是写作一份较为完善的NOIP难度的动态规划总结,名为《解动态规划题的基本思考方式》。现在你看到的是这个写作计划最先发布的一部分。 背包问题是一个经典的动态规划模型。它既简单形象容易理解,又在某种程度上能够揭示动态规划的本质,故不少教材都把它作为动态规划部分的第一道例题,我也将它放在我的写作计划的第一部分。 读本文最重要的是思考。因为我的语言和写作方式向来不以易于理解为长,思路也偶有跳跃的地方,后面更有需要大量思考才能理解的比较抽象的内容。更重要的是:不大量思考,绝对不可能学好动态规划这一信息学奥赛中最精致的部分。 Ŀ¼ 第一讲 01背包问题 这是最基本的背包问题,每个物品最多只能放一次。 第二讲 完全背包问题 第二个基本的背包问题模型,每种物品可以放无限多次。 第三讲 多重背包问题 每种物品有一个固定的次数上限。 第四讲 混合三种背包问题 将前面三种简单的问题叠加成较复杂的问题。 第五讲 二维费用的背包问题 一个简单的常见扩展。 第六讲 分组的背包问题 一种题目类型,也是一个有用的模型。后两节的基础。 第七讲 有依赖的背包问题 另一种给物品的选取加上限制的方法。 第八讲 泛化物品 我自己关于背包问题的思考成果,有一点抽象。 第九讲 背包问题问法的变化 试图触类旁通、举一反三。 附

背包问题之0-1背包,多重背包,完全背包简单模板(个人笔记,可能有误)

怎甘沉沦 提交于 2019-12-02 22:45:03
1 /* 2 背包问题简单的三类 0-1背包 多重背包 完全背包板子 3 */ 4 5 /* 6 0-1背包 7 */ 8 //普通做法 9 for(int i = 1; i <= n; i++){ 10 for(int j = w[i]; j <= c; j++){ 11 dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]); //前者为取 后者为不取 12 } 13 } 14 15 //空间复杂度优化 16 for(int i = 1; i <= n; i++){ 17 for(int j = c; j >= w[i]; j--){ 18 dp[j] = max(dp[j], dp[j-w[i]] + v[i]); 19 } 20 } 21 22 /* 23 多重背包 多重背包的解题思路是将相同的物品i看做是独立的个体从而将问题转换至0-1背包 24 */ 25 //普通做法(待验证) 26 for(int i = 1; i <= n; i++){ 27 for(int k = 1; k <= num[i]; k++){ 28 for(int j = w[i], j <= c; j++){ 29 if(w[i]*k <= j){ 30 dp[i][j] = max(dp[i-1][j], dp[i-1][j-k*w[i]] + k

leetcode 322

╄→尐↘猪︶ㄣ 提交于 2019-12-02 17:25:39
燎天一剑 7 个月前 这道题类似于完全背包问题,每个物品都可以无限使用,但是要求背包必须装满,而且要求背包中的物品数目最少, 归纳为数学问题就是, v[i]:代表每种硬币的价值 x[i]:代表每种硬币拿的个数,0<=x[i]<=amount/v[i] 所求问题可以归纳为: 在满足:amount=v1x1+v2x2+v3x3+...+vnxn 的条件下 求: target=min{x1+x2+x3+....xn} 最简单的一种思路就是把所有{xi}的组合全部拿出来,然后让target最小即可,利用递归就可以解决问题,但是时间复杂度会很高,但是如果有好的剪枝策略,也可以使用 另外一种方法就是常规的动态规划,利用一个amout+1长度的dp数组,记录每一个状态的最优解,过程见程序和注释 public int coinChange( int [] coins, int amount) { if (coins.length == 0 ) return -1 ; //声明一个amount+1长度的数组dp,代表各个价值的钱包,第0个钱包可以容纳的总价值为0,其它全部初始化为无穷大 //dp[j]代表当钱包的总价值为j时,所需要的最少硬币的个数 int [] dp = new int [amount+ 1 ]; Arrays.fill(dp, 1 ,dp.length,Integer.MAX

leetcode 322

≯℡__Kan透↙ 提交于 2019-12-02 17:20:36
燎天一剑 7 个月前 这道题类似于完全背包问题,每个物品都可以无限使用,但是要求背包必须装满,而且要求背包中的物品数目最少, 归纳为数学问题就是, v[i]:代表每种硬币的价值 x[i]:代表每种硬币拿的个数,0<=x[i]<=amount/v[i] 所求问题可以归纳为: 在满足:amount=v1x1+v2x2+v3x3+...+vnxn 的条件下 求: target=min{x1+x2+x3+....xn} 最简单的一种思路就是把所有{xi}的组合全部拿出来,然后让target最小即可,利用递归就可以解决问题,但是时间复杂度会很高,但是如果有好的剪枝策略,也可以使用 另外一种方法就是常规的动态规划,利用一个amout+1长度的dp数组,记录每一个状态的最优解,过程见程序和注释 public int coinChange( int [] coins, int amount) { if (coins.length == 0 ) return -1 ; //声明一个amount+1长度的数组dp,代表各个价值的钱包,第0个钱包可以容纳的总价值为0,其它全部初始化为无穷大 //dp[j]代表当钱包的总价值为j时,所需要的最少硬币的个数 int [] dp = new int [amount+ 1 ]; Arrays.fill(dp, 1 ,dp.length,Integer.MAX

python常用算法(6)——贪心算法,欧几里得算法

夙愿已清 提交于 2019-12-02 15:13:01
1,贪心算法   贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的的时在某种意义上的局部最优解。   贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算。贪心算法和其他算法比较有明显的区别,动态规划每次都是综合所有问题的子问题的解得到当前的最优解(全局最优解),而不是贪心地选择;回溯法是尝试选择一条路,如果选择错了的话可以“反悔”,也就是回过头来重新选择其他的试试。 1.1 找零问题   假设商店老板需要找零 n 元钱,钱币的面额有100元,50元,20元,5元,1元,如何找零使得所需钱币的数量最少?(注意:没有10元的面额)   那要是找376元零钱呢? 100*3+50*1+20*1+5*1+1*1=375   代码如下: # t表示商店有的零钱的面额 t = [100, 50, 20, 5, 1] # n 表示n元钱 def change(t, n): m = [0 for _ in range(len(t))] for i, money in enumerate(t): m[i] = n // money # 除法向下取整 n = n % money # 除法取余 return m, n print(change(t, 376)) # ([3,

背包问题的分支界限算法

ε祈祈猫儿з 提交于 2019-12-02 13:01:09
背包问题,分支界限算法 注释和思路都在代码里了。。 递归+剪枝优化 分支界限,就是根据条件来剪枝,条件边界就叫做界,求是否满足条件的过程就叫作代价函数 不能 直接 copy代码的 代码 #include<bits/stdc++.h> using namespace std; int n; //物品数量 int limitWeight; //背包上限重量 const int maxn = 1010; int bestValue = 0; //最优值 背包能装的最大价值 //物品node 两个属性 价值 和 重量 struct node{ int v; int w; }; //定义排序规则 bool cmp(node a,node b){ double flag1 = a.v*1.0/a.w; double flag2 = b.v*1.0/b.w; return flag1 > flag2; //按价值与重量比排序 } struct node nod[maxn];//存放物品的结构体数组 int takeNum[maxn]; //记录拿物品的数量 int bestTake[maxn]; //记录最优的 拿物品的数量 //第x个物品时 当前背包的重量 code by:fishers void dfs(int x,int curWeight,int curValue){ if(x == n

超大背包问题

萝らか妹 提交于 2019-12-02 10:55:19
题目: 特大背包问题 (20分) C时间限制:1000 毫秒 | C内存限制:10000 Kb 题目内容: 现在有一个容量为C的背包和N个重量和价值已知的物品. 现在要从这n个物品中挑选出一些物品, 使得选择的物品的总重量不超过背包的容量, 且总价值最大. 此题的数据范围: 1 <= C <= 10^8(10的8次方) 1 <= N <= 100 输入描述 有多组测试数据. 第一行一个正整数T(T<=15), 表示测试数据组数. 对于每组测试数据: 第一行两个正整数N和C, 分别表示物品的数量和背包的容量. 接下来N行, 每行两个正整数w,v ,分别表示对应物品的重量和价值(1<= w <= 10^7, 1<= v <= 100) 输出描述 输出一个正整数, 表示在所选物品不超过背包容量的情况下, 能够得到的最大价值. 输入样例 1 3 10 5 10 5 10 4 12 输出样例 22 ———————————————— 思路: 先求出所有物品的总价值V, 用一个一维数组,下标对应价值,数组储存总价值依次减小时需要的最小容量,。 最后输出 题目所给背包容量对应的价值即为所求答案。 核心代码: for(i=1;i<=n;i++) for(int j = V ;j >= v[i];j--) dp[j]= min( dp[j] , dp[j-v[i]] + w [i]); 通过代码 :