背包问题

动态规划之背包问题

雨燕双飞 提交于 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 背包这个名词的来历。 解决这个问题没有什么排序之类巧妙的方法,只能穷举所有可能,根据我们「动态规划详解」中的套路,直接走流程就行了。 动规标准套路 看来我得每篇动态规划文章都得重复一遍套路,历史文章中的动态规划问题都是按照下面的套路来的。 第一步要明确两点,「状态」和「选择」 。 先说状态,如何才能描述一个问题局面?只要给几个物品和一个背包的容量限制,就形成了一个背包问题呀。 所以状态有两个,就是「背包的容量」和

HDU 2844 Coins 多重背包

送分小仙女□ 提交于 2020-03-09 15:56:36
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2844 Coins Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 32768/32768 K (Java/Others) 问题描述 Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch. You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of

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 ] ,

01背包的内循环逆序解析

佐手、 提交于 2020-03-08 14:31:50
背包九讲:01背包的内循环逆序问题 对于01背包,用二维数组做DP的情况如下: F[i,v]代表,在背包容量为v的情况下,从前i件物品中选出若干件(因背包容量的限制,可能不会所有i件都在里面,取最大值时背包里应该是权值相对较大的那些物品)所能得到的最大价值。 第一句对dp设置初始条件。 两个for循环遍历所有的情况:i从1~N表示从i件物品中选取,v从ci~V表示背包的大小(现在考虑的是第i件物品的放与不放,因此背包应该至少大于等于i物品的费用,否则无意义) 最关键的问题在于max{F[i-1,v],F[i-1,v-Ci]+wi}这一句 F[i-1,v]表示在背包容量v的情况下,从前i-1个物品中怎样放置使价值最大,这也代表, 对于第i件物品,我们不选择将它放入背包 ,而去从前i-1个物品中选择放置策略,但这与F[i-1,v-Ci]是不同的,因为我们现在只是选择不把这个i放进去,而不代表我们要削减背包的容量。 F[i-1,v-Ci]+wi表示,在背包容量为v的情况下, 我们选择将这个第i件物品放入背包的情况。此时F[i,v]应该是,在放入之前背包的最大价值,加上放入之后的最大价值。而放入之前背包的最大价值为F[i-1,v-Ci]。 仔细思考F[i-1,v]与F[i-1,v-Ci]的区别: 现在我们计算的是F[i,v],也就是说背包的容量已经定死为v了,F[i-1,v

0-1背包问题(python)

好久不见. 提交于 2020-03-06 16:43:26
解决办法:声明一个 大小为 m[n][c] 的二维数组. m[ i ][ j ] 表示 在面对第 i 件物品,且背包容量为 j 时所能获得的最大价值 (1). j < w[i] 的情况,这时候背包容量不足以放下第 i 件物品,只能选择不拿 m[ i ][ j ] = m[ i-1 ][ j ] (2). j>=w[i] 的情况,这时背包容量可以放下第 i 件物品,我们就要考虑拿这件物品是否能获取更大的价值。 如果拿取,m[ i ][ j ]=m[ i-1 ][ j-w[ i ] ] + v[ i ]。 这里的m[ i-1 ][ j-w[ i ] ]指的就是考虑了i-1件物品,背包容量为j-w[i]时的最大价值,也是相当于为第i件物品腾出了w[i]的空间。 如果不拿,m[ i ][ j ] = m[ i-1 ][ j ] , 同(1) # n:物品数量 # c:书包能承受的重量 # w:每个物品的重量 # v:每个物品的价值 #value[i][j]:遇到第i个物品,此时称重为j的书包价值 value = [ [ 0 for j in range ( c + 1 ) ] for i in range ( n + 1 ) ] def bag ( n , c , w , v ) : for i in range ( 1 , n + 1 ) : for j in range ( 1 , c

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 (

PHP经典算法之背包问题

血红的双手。 提交于 2020-03-04 00:06:06
问题 :假设有一个背包的负重最多可达8公斤,而希望在背包中装入负重范围内可得之总价物品,假设是水果好了,水果的编号、单价与重量如下所示: 1 栗子 4KG $4500 2 苹果 5KG $5700 3 橘子 2KG $2250 4 草莓 1KG $1100 5 甜瓜 6KG $6700 分析:背包问题是关于最佳化的问题,要解最佳化问题可以使用「动态规划」(Dynamic programming),从空集合开始,每增加一个元素就先求出该阶段的最佳解,直到所有的元素加入至集合中,最后得到的就是最佳解。 源码 : //背包承重上限 $limit = 8; //物品种类 $total = 5; //物品 $array = array( array("栗子", 4, 4500), array("苹果", 5, 5700), array("橘子", 2, 2250), array("草莓", 1, 1100), array("甜瓜", 6, 6700) ); //存放物品的数组 $item = array_fill(0, $limit + 1, 0); //存放价值的数组 $value = array_fill(0, $limit + 1, 0); $p = $newvalue = 0; for ($i = 0; $i < $total; $i++) { for ($j = $array[$i

背包

北慕城南 提交于 2020-03-02 12:16:31
文章目录 01背包 [Bone Collector](http://acm.hdu.edu.cn/showproblem.php?pid=2602) [P2925 [USACO08DEC]干草出售Hay For Sale](https://www.luogu.com.cn/problem/P2925) 完全背包 [P1616 疯狂的采药](https://www.luogu.com.cn/problem/P1616) 多重背包 [P1776 宝物筛选](https://www.luogu.com.cn/problem/P1776) 01背包 问题描述:容量为V的背包,n件物品,每件物品的价值为v[i],占空间为w[i],尽量让背包装的价值大。 解法: 寻找递推关系式: 面对当前的物品有两种选择: (1)不选择,那么此时的价值与前面的价值相同,v[i][j]=v[i-1][j] (2)选上,那么此时的价值就是前面的总物品的价值加上当前物品的价值,容量减去当前物品的容量 v[i][j]=v[i-1][j-w[i]]+v[i] 如果现在总的容量不够,那么只能不选。 所以推出关系式v[i][j]=max(v[i-1][j],v[i-1][j-w[i]]+v[i]). Bone Collector #include<cstdio> #include<cstring> #include

Vijos 1180 (树形DP+背包)

孤街浪徒 提交于 2020-02-29 12:39:46
题目链接 : https://vijos.org/p/1180 题目大意 :选课。只有根课选了才能选子课,给定选课数m, 问最大学分多少。 解题思路 : 树形背包。cost=1。 且有个虚根0,取这个虚根也要cost,所以最后的结果是dp[0][m+1]。 本题是cost=1的特殊背包问题,在两个for循环上有一个优化。 for(f+1...j....cost) for(1....k...j-cost) 其中f为当前已经dfs子结点个数。之所以+1,是因为根要预留一个空间。 f+=dfs(t),dfs(t)返回的是子点t的f+1。 其实可以直接把f+1写成m+1, 不过要多好多次没必要的循环。 这种写法在 POJ 1155 点数量庞大时,将起决定性作用。 #include "iostream" #include "cstdio" #include "cstring" using namespace std; #define maxn 305 int n,m,root,x; int dp[maxn][maxn],head[maxn],w[maxn],tol; struct Edge { int to,next; }e[maxn]; void addedge(int u,int v) { e[tol].to=v; e[tol].next=head[u]; head[u]=tol++;