背包问题动态规划

动态规划算法(@背包问题)

早过忘川 提交于 2020-03-14 08:24:01
 动态规划(Dynamic programming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。    动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许 多 子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同 一个 子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。   关于动态规划最经典的问题当属背包问题。 算法步骤: 1. 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。 2. 子 问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多 次。 动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题 时,只是 在表格中简单地查看一下结果

动态规划之背包问题

雨燕双飞 提交于 2020-03-10 13:28:13
后台天天有人问背包问题,这个问题其实不难啊,如果我们号动态规划系列的十几篇文章你都看过,借助框架,遇到背包问题可以说是手到擒来好吧。无非就是状态 + 选择,也没啥特别之处嘛。 今天就来说一下背包问题吧,就讨论最常说的 0-1 背包问题。描述: 给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 wt[i] ,价值为 val[i] ,现在让你用这个背包装物品,最多能装的价值是多少? 举个简单的例子,输入如下: N = 3, W = 4 wt = [2, 1, 3] val = [4, 2, 3] 算法返回 6,选择前两件物品装进背包,总重量 3 小于 W ,可以获得最大价值 6。 题目就是这么简单,一个典型的动态规划问题。这个题目中的物品不可以分割,要么装进包里,要么不装,不能说切成两块装一半。这就是 0-1 背包这个名词的来历。 解决这个问题没有什么排序之类巧妙的方法,只能穷举所有可能,根据我们「动态规划详解」中的套路,直接走流程就行了。 动规标准套路 看来我得每篇动态规划文章都得重复一遍套路,历史文章中的动态规划问题都是按照下面的套路来的。 第一步要明确两点,「状态」和「选择」 。 先说状态,如何才能描述一个问题局面?只要给几个物品和一个背包的容量限制,就形成了一个背包问题呀。 所以状态有两个,就是「背包的容量」和

01背包问题

喜夏-厌秋 提交于 2020-03-09 08:37:02
【题目描述】 一个旅行者有一个最多能装 M 公斤的背包,现在有 n 件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn,求旅行者能获得最大总价值。 【输入】 第一行:两个整数,M(背包容量,M≤200)和N(物品数量,N≤30); 第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。 【输出】 仅一行,一个数,表示最大总价值。 【输入样例】 10 4 2 1 3 3 4 5 7 9 【输出样例】 12 动态规划的方法 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #define N 1001 using namespace std; int m,n; int w[N],c[N],f[N]; void fun(int cost,int weight) { for(int v=m;v>=weight;v--) f[v]=max(f[v],f[v-weight]+cost); } int main(){ cin>>m>>n; for(int i=1; i<=n; ++i) cin>>w[i]>>c[i]; for(int i=1; i<=n; ++i){ fun(c[i],w[i]); } cout<<f[m]<<endl;

动态规划,0/1背包,完全背包

时光怂恿深爱的人放手 提交于 2020-03-08 21:55:12
动态规划 动态规划问题的一般形式就是求最值。 求解动态规划的核心问题是穷举。 动态规划的穷举有点特别,因为这类问题存在「重叠子问题」,如果暴力穷举的话效率会极其低下,所以需要「备忘录」或者「DP table」来优化穷举过程,避免不必要的计算。 而且,动态规划问题一定会具备「最优子结构」,才能通过子问题的最值得到原问题的最值。 关键就是状态转移方程,写出正确的状态转移方程,才能正确地枚举。 解决问题步骤: 明确「状态」 -> 定义 dp 数组/函数的含义 -> 明确「选择」(做出选择改变当前状态-> 明确 base case。 0/1背包问题 描述: 有N件物品和一个容量为V的背包。第i件物品的费用(即体积,下同)是w[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 思路: 用动态规划的思路,阶段就是“物品的件数”,状态就是“背包剩下的容量”,那么很显然f [ i , v ] 就设为从前 i 件物品中选择放入容量为 v 的背包最大的价值。那么状态转移方程为: f[i][v]=max{ f[i-1][v],f[i-1][v-w[i]]+val[i] }。 这个方程可以如下解释:只考虑子问题“将前 i 个物品放入容量为 v 的背包中的最大价值”那么考虑如果不放入 i ,最大价值就和 i 无关,就是 f[ i - 1 ][ v ] ,

C++:动态规划(2)背包问题

帅比萌擦擦* 提交于 2020-03-06 01:50:07
找这个阶段的状态和上各阶段的状态关系 01背包:每件商品只有一件 dp[i][v]:前i件物品恰好装入v的背包中的最大价值 状态: 放i,求前i-1件商品恰好装入v-w[i]的背包中的最大价值+第i件商品的价值。 不放i,求前i-1件商品恰好装入v的背包中的最大价值。 状态转移方程: 都是求最大价值 dp[i][v]=max( dp[i-1][v] , dp[i-1][v-w[i]]+c[i] ) 通过边界dp[0][v]=0(0<=v<=V) 01背包 二维数组的放与不放 int dp[maxn][maxn]; void _01dp() { int maxd = 0; memset(dp, 0, sizeof(dp)); //边界 for (int i = 0; i < V; i++) { dp[0][i] = 0; } for (int i = 1; i <=N; i++) { for (int v = w[i]; v <= V; v++) { dp[i][v] = max(dp[i - 1][v], dp[i - 1][v - w[i]]+c[i]); maxd = max(maxd, dp[i][v]); } } cout << maxd << endl; } 优化,体积从V-》w[i] 逆序发展 ;不需要物品i了,直接变为有这个商品的体积,和没有 dp[v]=max (

动态规划——背包问题

倖福魔咒の 提交于 2020-02-28 15:17:10
在写博客之前,先列出两个背包九讲链接以供参考 yxc在B站上讲的背包九讲: 背包九讲专题 以及一篇非常经典的 dd大牛的《背包九讲》 0 1背包问题 完全背包问题 多重背包问题 分组背包问题 0 1背包问题 有N件物品和一个容量为V的背包。第i件物品的费用是c[i](本题里是v[i]),价值是w[i]。 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 在求状态转移方程的方面,思路是集合划分: f(i,j):“在i个东西里面选质量为j的东西的总商品价值”这一集合可分为“选的所有东西里面 不包含i ”和“选的东西里面 包含i ”两种情况。 的话 不含i的情况即是f(i-1,j)【在i-1个东西中选质量为j的东西】 含i的情况即是f(i-1,j-V i )+w i 【由于选了i,那就是在i-1个东西中选j-V i 质量的总价值加上i的价值】 将上述两个集合取价值最大的取法,即为“在i个东西里面选质量为j的东西的总商品价值” 优化1:减少操作次数 由于上述的情况中,含i的情况是不一定存在的(那是当背包最大重量j<V i 即装不下的时候不需要考虑) 优化2:将二维数组优化为滚动数组 滚动数组:如果f(i)的计算仅仅只用了f(i-1)来完成计算的话,就只需要开一个f[2][N]的数组即可(可以运用e=1-e来实现滚动) 值得注意的是

多重背包问题的二进制优化

我们两清 提交于 2020-02-28 05:08:01
前情提要: 动态规划——背包九讲——多重背包问题 多重背包问题 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。 这题目和完全背包问题很类似,特点是:每种物品都有自己特异的件数、花费、价值。 朴素算法: 每种物品有n[i]件可以取用,需要枚举每种物品选了多少件(枚举件数不能超过背包容量) for ( int i = 1 ; i <= n ; i ++ ) for ( int j = 0 ; j <= m ; j ++ ) for ( int k = 0 ; k <= s [ i ] && k * v [ i ] <= j ; k ++ ) //与完全背包相比仅仅是加了一个判断条件而已 f [ i ] [ j ] = max ( f [ i ] [ j ] , f [ i - 1 ] [ j - v [ i ] * k ] + w [ i ] * k ) ; 朴素算法的时间效率很低,通过下面的二进制优化可以把遍历每种物品的n[i]件物品的时间复杂度从O(n)优化为O(log n) 优化:通过展开化简式子不可行,换用二进制优化方式 正篇:背包问题的经典二进制优化 第i种物品是有n[i]件的,这个n[i]可以被展开为n[i]=2 0 +2 1 +…+2 k +c (其中2 k+1 < n[i] < 2 k+2 ) (2 0 +2 1 +

数据结构——背包问题

折月煮酒 提交于 2020-02-23 14:22:26
引言 算法的经典问题之一 背包问题 ,背包问题是动态规划(运筹学)的一个典型的例子,它的问题描述即规定背包所能容纳的最大重量,然后此时有一批物品对应不同的质量和价值,那么如何放置物品进入背包使得背包中的价值最大。 通常情况下,背包问题会分为两种情形: 物品可以切开放置到背包中,即物品的重量和价值可以按分数的形式放置 物品只能以整数的形式放置 前一种情况,只能用贪心算法解决去解决问题。后一种情况,则需要通过动态规划。 背包问题(整数) 首先,我们先来认识一下动态规划解决问题的步骤: 定义子问题 实现要反复执行来解决子问题的部分 识别并求解出基线条件 然后假设此时我们有一个这样的背包问题: 此时有一个背包可容纳的重量为 7,分别有重量为 2、3、4 对应价值为 3、4、5 的三个物品 ,并分别命名为物品 1、物品 2、物品 3。要如何往背包中放置物品,才能使得背包中的价值最高? 对于从事编程的同学而言,遇到略显复杂的问题,我们应该先建立数学模型。而对于这个背包问题,它的数学模型是这样的: 背包所能容纳的重量 w: 5 物品 重量 价值 1 2 3 2 3 4 3 4 5 ( 矩阵的行数为物品数量 + 1 ,列为背包所能容纳重量 + 1 ,初始化默认 0 列 0 行为 0 ) 第一阶段 i / w 0 1 2 3 4 5 0 0 0 0 0 0 0 1 0 0 3 3 3 3 2 0 3

【DP_背包专辑】【from zeroclock's blog】

只愿长相守 提交于 2020-01-29 03:38:19
本文转自:zeroclock的博客 这短时间看了论文《背包九讲》,看到背包问题解法中的优美之处也看到背包问题在现实中的应用,总结出一句话:背包问题值得一看。 背包问题可以概括为这样的模型:有若干种选择,每种选择有一定的代价和价值,做某些选择会得到特定的状态,问我们在约定的条件下怎么得到特定的状态?这里的状态可以是代价和或者价值和或者由其他这两者组合而来的状态。这类问题需要枚举每种状态,但是可以通过动态规划减少枚举的次数,提高效率,主要思想是每次都利用前面得到的状态进行转移得到当前的状态。这类问题很少能用贪心的,首先,贪心很难证明策略是否正确,其次贪心必定使得枚举量大量减少,会导致结果错误。 个人认为背包九讲中的很多模型本质都是两种模型:01背包模型、完全背包模型。大家可以把这两种模型理解透彻,然后再看其他模型,这样必定事半功倍。 看《背包九讲》的过程中开了一个专题,大概26道题目,主要是Hdu和Poj的题目,题目有难有易,这次的专辑主要讲解这些题目,还有一些Uva的简单背包问题也会加入到这个专辑中。本专辑都只列举基本思路,如果大家想看详细思路或者代码请去我博客中查找,大部分题目我都有写解题报告。 一、01背包问题 (先枚举物品,再逆序枚举容量) 1、Hdu 2602 Bone Collector 非常常规的01背包问题,用一维和二维数组都可以做,一维快相当多。 1 //二维0

彻底理解0-1背包问题

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-18 05:40:07
0-1背包问题概念 背包问题本质是个求最优解的问题: 有个背包有V大小的空间可以存放物品,现在有n个物品,每个物品体积分别为v1、v2...、vn,价值分别为w1、w2...、wn。现在求解: 如何使物品尽可能多的放在背包中,使得背包中的物品总价值最大? 0-1背包问题指的是每个物品只能使用一次 解决这类问题,大致有2类方法: 递归算法、动态规划算法 ,下面详细讲解3种算法(借鉴了 博主的论文 )。 一、递归算法 递归算法解决这类问题大致的核心思想: 我们用B[k][C]表示前k个物品放进容量为C的背包里,得到的最大的价值。 我们用自顶向下的角度来看,假如我们已经进行到了最后一步(即求解将k个物品放到背包里获得的最大价值),此时我们便有两种选择: 1、不放第k个物品,此时总价值为B[k−1][C] 2、放置第k个物品,此时总价值为wk+B[k−1][C−vk] 两种选择中总价值最大的方案就是我们的最终方案,递推式(有时也称之为状态转移方程)如下 B[k][C]=max(B[k-1][C],wk+B[k−1][C−wk]) 编程如下: public class test { //物品总量,最大承重 static int N = 6; static int W = 21; static int[][] B = new int[N][W]; static String[][] B_ =