动态规划经典案例详解(背包问题)

合集下载

[编程题]【动态规划】背包问题

[编程题]【动态规划】背包问题

[编程题]【动态规划】背包问题[编程题]【动态规划】背包问题题⽬信息问题:现有背包。

其中有四个商品。

价值-体积如下* 物品编号: 1 2 3 4* 物品体积: 2 3 4 5* 物品价值: 3 4 5 6* 问:如何才能保证在背包容量为8的情况下装的价值最⼤?思路背包问题,动态规划思路1、构建dp表,dp【i】【j】代表该i编号的背包为⽌容量为j的最⼤价值。

先填表加深理解。

2、填完表如果要找出价值为k的容量的背包加⼊的物品标号只需要从i=dp.length-1,j=k的dp数组元素处回溯。

填完表如下(借视频中up主的结果):总结结论如下(借视频中up主的总结):理解了上述总结的思路,其实代码就很容易写出来了。

代码如下Java代码package interviewcode;import ng.annotation.Target;import java.util.ArrayList;import java.util.Arrays;* @author* @create 2020/8/11 - 10:52* @descp:* 问题:现有背包。

其中有四个商品。

价值体积如下* 物品编号: 1 2 3 4* 物品体积: 2 3 4 5* 物品价值: 3 4 5 6* 问:如何才能保证在背包容量为8的情况下装的价值最⼤?** 步骤1:填表之后的结果:* 0 0 0 0 0 0 0 0 0* 0 0 3 3 3 3 3 3 3* 0 0 3 4 4 7 7 7 7* 0 0 3 4 5 7 8 9 9* 0 0 3 4 5 7 8 9 10* 步骤2:回溯*///⽅法:动态规划public class P28_背包问题 {public static void main(String[] args) {int[] size = new int[]{0,2,3,4,5}; //第0位放⼀个默认的0值,为了下边⽅便取size[i]就为i号物品的体积int[] money = {0,3, 4, 5, 6}; //第0位放⼀个默认的0值,为了下边⽅便取money[i]就为i号物品的价值int target = 14; //指定的背包⼤⼩//调⽤int[][] ints = dpWrite(size, money, target);ArrayList<Integer> huisu = huisu(ints, size, target);System.out.println("您输⼊的背包⼤⼩是:"+target);System.out.println("添加的物品编号是:"+huisu);System.out.println("最⼤价值:"+ints[size.length-1][target]);}public static int[][] dpWrite(int[] size,int[] money,int targetValue){//这⾥构造⼀个例如4*8的dp,⾏代表截⽌到i背包的最优组合的价值,j代表的背包的容量值int[][] dp = new int[size.length][targetValue+1];//初始化第0⾏的值for(int j=0;j<=targetValue;j++){dp[0][j] = 0;}//初始化第⼀列的值for(int i=1;i<size.length;i++){dp[i][0] = 0;//dp[i][1] = 0;}//初始化中间值ifor(int i=1;i<size.length;i++){for (int j=1;j<=targetValue;j++){//如果第i号背包的体积⼩于当前的j背包容量,就保持和dp[i-1]值相同,即没放⼊if(size[i]>j){dp[i][j] = dp[i-1][j];}else{/*即如果当前i号物品体积可以放⼊的话,就看预留该体积后剩余的价值在i-1号物品中的最⼤值加上该物品的价值和是否是⼤于dp[i-1][j]的值,谁⼤取谁*/dp[i][j] = Math.max(dp[i-1][j-size[i]>0?j-size[i]:0]+money[i],dp[i-1][j]);}}}//这样就填表完成了。

动态规划——背包问题python实现(01背包、完全背包、多重背包)

动态规划——背包问题python实现(01背包、完全背包、多重背包)

动态规划——背包问题python实现(01背包、完全背包、多重背包)参考:⽬录描述:有N件物品和⼀个容量为V的背包。

第i件物品的体积是vi,价值是wi。

求解将哪些物品装⼊背包,可使这些物品的总体积不超过背包流量,且总价值最⼤。

⼆维动态规划f[i][j] 表⽰只看前i个物品,总体积是j的情况下,总价值最⼤是多少。

result = max(f[n][0~V]) f[i][j]:不选第i个物品:f[i][j] = f[i-1][j];选第i个物品:f[i][j] = f[i-1][j-v[i]] + w[i](v[i]是第i个物品的体积)两者之间取最⼤。

初始化:f[0][0] = 0 (啥都不选的情况,不管容量是多少,都是0?)代码如下:n, v = map(int, input().split())goods = []for i in range(n):goods.append([int(i) for i in input().split()])# 初始化,先全部赋值为0,这样⾄少体积为0或者不选任何物品的时候是满⾜要求dp = [[0 for i in range(v+1)] for j in range(n+1)]for i in range(1, n+1):for j in range(1,v+1):dp[i][j] = dp[i-1][j] # 第i个物品不选if j>=goods[i-1][0]:# 判断背包容量是不是⼤于第i件物品的体积# 在选和不选的情况中选出最⼤值dp[i][j] = max(dp[i][j], dp[i-1][j-goods[i-1][0]]+goods[i-1][1])print(dp[-1][-1])⼀维动态优化从上⾯⼆维的情况来看,f[i] 只与f[i-1]相关,因此只⽤使⽤⼀个⼀维数组[0~v]来存储前⼀个状态。

那么如何来实现呢?第⼀个问题:状态转移假设dp数组存储了上⼀个状态,那么应该有:dp[i] = max(dp[i] , dp[i-v[i]]+w[i])max函数⾥⾯的dp[i]代表的是上⼀个状态的值。

动态规划法求01背包问题

动态规划法求01背包问题

动态规划法求01背包问题思路状态表⽰:f[i][j]表⽰前i个物品在容量为j的背包下的最⼤价值v[i]表⽰第i个物品的价值,w[i]表⽰第i个物品的重量状态转换:对于第i个物品如果当前背包不可以装下这个物品,那么当前的f[i][j] = f[i - 1][j],也就是上⼀个状态的最⼤价值如果当前背包可以装下这个物品,那么当前的f[i][j] = f[i - 1][j - v[i]] + w[i]和f[i - 1][j]取较⼤的那⼀个,第⼀个是考虑把第i个物品装⼊背包,那么背包物品的价值就是前i-1个物品装⼊容量为j-w[i]再加上第i个物品v[i]的价值,第⼆个是不把当前物品装⼊背包的价值,两个取⼤的那⼀个作为最优解代码详解:1. 0/1背包问题#include<iostream>using namespace std;const int N = 1e3 + 10;int f[N], w[N], v[N];int main(){int n, c;cin >> n >> c;for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++)for(int j = c; j >= 0 && j >= v[i]; j --)f[j] = max(f[j], f[j - v[i]] + w[i]);cout << f[c] << endl;return 0;}}完全背包问题(每个物品可以使⽤⽆数次f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])完全背包问题本来应该是在背包问题上再加⼀个循环的,但是可以推导出下⾯这个样⼦f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])为什么呢,只是把0/1背包问题的f[i - 1][j - v[i] + w[i])的i-1换成了i就可以了?从头来说:完全背包问题,对于第i个物品,假设剩下的背包容量还可以装n个这个物品,那么⼀共就有n+1中决策⽅案,还有⼀种⽅案就是⼀个都不选那么对于第i个物品:它的最⼤价值就是f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]), f[i - 1][j - 2 * v[i]] + 2 * w[i]....)⼀直到n为⽌(①式)令 j = j - v[i] 那么f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i].....)(②式)然后发现⼆式中的右边⽐较像⼀式中的第⼆项到最后⼀项,就是每⼀项都少了⼀个w[i]把⼆式带⼊⼀式,那么⼀式就是 f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]), 就是下⾯这个状态⽅程啦 ;#include<iostream>using namespace std;const int N = 1e3 + 10;int f[N][N], w[N], v[N];int main(){int n, c;cin >> n >> c;for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ ){for(int j = 1; j <= c; j ++ ){f[i][j] = f[i - 1][j];if(j >= v[i])f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);}}cout << f[n][c] << endl;return 0;}完全背包优化:#include<iostream>using namespace std;const int N = 1e3 + 10;int f[N], w[N], v[N];int main(){int n, c;cin >> n >> c;for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i]; for(int i = 1; i <= n; i ++ )for(int j = v[i]; j <= c; j ++ )//从前往后更新 f[j] = max(f[j], f[j - v[i]] + w[i]);cout << f[c] << endl;return 0;}。

二维背包问题经典例题

二维背包问题经典例题

二维背包问题经典例题
二维背包问题是一个经典的动态规划问题,下面是一个具体的例题:
题目描述:
有N件物品和一个容量是V的背包,背包能承受的最大重量是M。

每件物品只能用一次。

体积是vi,重量是mi,价值是wi。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。

输出最大价值。

输入格式:
第一行两个整数,N,V,M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。

接下来有N行,每行三个整数vi,mi,wi,用空格隔开,分别表示第i件物品的体积、重量和价值。

输出格式:
输出一个整数,表示最大价值。

输入样例:
4 5 6
1 2 32
4 4 43
4 5 54
5 6 6
输出样例:8
思路分析:
二维背包问题可以通过建立一个三维数组f[i][j][k]来解决,其中f[i][j][k]表示在前i个物品中选出体积不超过j、质量不超过k的物品的最大价值。

状态转移方程为f[i][j][k]=max(f[i-1][j][k], f[i-1][j-v][k-m]+w),其中v表示第i个物品的体
积,m表示第i个物品的质量,w表示第i个物品的价值。

由于数组是三维的,因此可以使用滚动数组来优化空间复杂度。

具体实现时,可以将j和k的枚举顺序改为从大到小,以防止需要用到的状态被覆盖。

动态规划-01背包问题

动态规划-01背包问题

动态规划——01背包问题01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻。

01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }f[i,j]表示在前i件物品中选择若干件放在承重为j 的背包中,可以取得的最大价值。

Pi表示第i件物品的价值。

决策:为了背包中物品总价值最大化,第i件物品应该放入背包中吗?题目描述:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?只要你能通过找规律手工填写出上面这张表就算理解了01背包的动态规划算法。

首先要明确这张表是至底向上,从左到右生成的。

为了叙述方便,用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e 时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。

对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。

同理,c2=0,b2=3,a2=6。

对于承重为8的背包,a8=15,是怎么得出的呢?根据01背包的状态转换方程,需要考察两个值,一个是f[i-1,j],对于这个例子来说就是b8的值9,另一个是f[i-1,j-Wi]+Pi;在这里, f[i-1,j]表示我有一个承重为8的背包,当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]表示我有一个承重为6的背包(等于当前背包承重减去物品a的重量),当只有物品b,c,d,e四件可选时,这个背包能装入的最大价值f[i-1,j-Wi]就是指单元格b6,值为9,Pi指的是a物品的价值,即6由于f[i-1,j-Wi]+Pi = 9 + 6 = 15 大于f[i-1,j] = 9,所以物品a应该放入承重为8的背包以下是actionscript3 的代码[java]view plain copy1.public function get01PackageAnswer(bagItems:Array,bagSize:int):Array2.{3. var bagMatrix:Array=[];4. var i:int;5. var item:PackageItem;6.for(i=0;i<bagItems.length;i++)7. {8. bagMatrix[i] = [0];9. }10.for(i=1;i<=bagSize;i++)11. {12.for(var j:int=0;j<bagItems.length;j++)13. {14. item = bagItems[j] as PackageItem;15.if(item.weight > i)16. {17.//i背包转不下item18.if(j==0)19. {20. bagMatrix[j][i] = 0;21. }22.else23. {24. bagMatrix[j][i]=bagMatrix[j-1][i];25. }26. }27.else28. {29.//将item装入背包后的价值总和30. var itemInBag:int;31.if(j==0)32. {33. bagMatrix[j][i] = item.value;34.continue;35. }36.else37. {38. itemInBag = bagMatrix[j-1][i-item.weight]+item.value;39. }40. bagMatrix[j][i] = (bagMatrix[j-1][i] > itemInBag ? bagMatrix[j-1][i] : itemInBag)41. }42. }43. }44.//find answer45. var answers:Array=[];46. var curSize:int = bagSize;47.for(i=bagItems.length-1;i>=0;i--)48. {49. item = bagItems[i] as PackageItem;50.if(curSize==0)51. {52.break;53. }54.if(i==0 && curSize > 0)55. {56. answers.push();57.break;58. }59.if(bagMatrix[i][curSize]-bagMatrix[i-1][curSize-item.weight]==item.value)60. {61. answers.push();62. curSize -= item.weight;63. }64. }65.return answers;66.}PackageItem类[java]view plain copy1.public class PackageItem2.{3.public var name:String;4.public var weight:int;5.public var value:int;6.public function PackageItem(name:String,weight:int,value:int)7. { = name;9.this.weight = weight;10.this.value = value;11. }12.}测试代码[java]view plain copy1.var nameArr:Array=['a','b','c','d','e'];2.var weightArr:Array=[2,2,6,5,4];3.var valueArr:Array=[6,3,5,4,6];4.var bagItems:Array=[];5.for(var i:int=0;i<nameArr.length;i++)6.{7. var bagItem:PackageItem = new PackageItem(nameArr[i],weightArr[i],valueArr[i]);8. bagItems[i]=bagItem;9.}10.var arr:Array = ac.get01PackageAnswer(bagItems,10);出师表两汉:诸葛亮先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。

python背包问题例题

python背包问题例题

python背包问题例题背包问题是一个经典的组合优化问题,其目标是在给定的一组物品中选择一些物品放入背包,使得背包中物品的总价值最大,同时限制背包的总重量不超过一定值。

下面给出一个简单的例题来说明背包问题:假设有以下物品:物品1:重量2,价值3物品2:重量3,价值4物品3:重量4,价值5物品4:重量5,价值6现在有一个背包,其最大承重为10。

问如何选择物品放入背包,使得背包中物品的总价值最大?针对这个问题,我们可以使用动态规划的方法来解决。

定义一个二维数组dp,其中dp[i][j]表示将前i个物品放入承重为j的背包中所能达到的最大价值。

首先,考虑边界情况:当i=0或j=0时,dp[i][j]均为0,表示没有物品可选或者背包承重为0,此时背包中的总价值为0。

然后,我们可以通过以下递推关系来更新dp数组:若第i个物品的重量wi小于等于j,则可以选择将物品i放入背包中,此时背包中的总价值为dp[i-1][j-wi]+vi,即考虑前i-1个物品放入承重为j-wi的背包中所能达到的最大价值,再加上第i个物品的价值vi。

若第i个物品的重量wi大于j,则无法选择将物品i放入背包中,此时背包中的总价值仍然为dp[i-1][j]。

最终,dp中的最后一个元素dp[n][m](n为物品个数,m为背包的最大承重)即为所求的最优解。

对于给定的例题,可以得到以下dp数组:0 0 0 0 0 0 0 0 0 0 00 0 3 3 3 3 3 3 3 3 30 0 3 4 4 7 7 7 7 7 70 0 3 4 5 7 8 9 9 12 120 0 3 4 5 7 8 9 10 12 13其中,dp[4][10]为最终的最大价值,即13。

根据dp数组的构造过程,我们还可以知道选择的物品为1、3、4,其总重量为11,总价值为13。

这就是背包问题的一个简单例题的解答过程。

在实际应用中,背包问题可以有更多的约束条件和变种形式,需要根据具体情况选择合适的算法和策略来解决。

动态规划方案解决算法背包问题实验报告含源代码

动态规划方案解决算法背包问题实验报告含源代码

动态规划方案解决算法背包问题实验报告含嘿,大家好!今天我来给大家分享一个相当有趣的编程问题——背包问题。

这可是算法领域里的经典难题,也是体现动态规划思想的好例子。

我会用我10年的方案写作经验,给大家带来一份详细的实验报告,附带哦!让我简单介绍一下背包问题。

假设你是一个盗贼,要盗取一个博物馆里的宝贝。

博物馆里有n个宝贝,每个宝贝都有它的价值v和重量w。

你有一个承重为W的背包,你希望放入背包的宝贝总价值最大,但总重量不能超过背包的承重。

这个问题,就是我们要解决的背包问题。

一、算法思路1.创建一个二维数组dp,dp[i][j]表示前i个宝贝放入一个承重为j的背包中,能达到的最大价值。

2.初始化dp数组,dp[0][j]=0,因为如果没有宝贝,那么无论背包承重多少,价值都是0。

3.遍历每个宝贝,对于每个宝贝,我们有两种选择:放入背包或者不放入背包。

4.如果不放入背包,那么dp[i][j]=dp[i-1][j],即前i-1个宝贝放入一个承重为j的背包中,能达到的最大价值。

5.如果放入背包,那么dp[i][j]=dp[i-1][j-w[i]]+v[i],即前i-1个宝贝放入一个承重为j-w[i]的背包中,加上当前宝贝的价值。

6.dp[i][j]取两种情况的最大值。

二、defknapsack(W,weights,values,n):dp=[[0for_inrange(W+1)]for_inrange(n+1)]foriinrange(1,n+1):forjinrange(1,W+1):ifj>=weights[i-1]:dp[i][j]=max(dp[i-1][j],dp[i-1][j-weights[i-1]]+values[i -1])else:dp[i][j]=dp[i-1][j]returndp[n][W]测试数据W=10weights=[2,3,4,5]values=[3,4,5,6]n=len(values)输出结果max_value=knapsack(W,weights,values,n)print("最大价值为:",max_value)三、实验结果分析通过上面的代码,我们可以得到最大价值为15。

5.5动态规划求解01背包问题

5.5动态规划求解01背包问题
xn-1: 若xn=0,则判断(Pl,Wl)∈ Sn-2?,以确定Xn-1的值 若xn=1,则依据(Pl-pn,Wl-wn)∈ Sn-2?,以判断Xn-1的值
xn-2,…,x1将依次推导得出
例2的解向量推导
S0={(0,0)}
S1={(0,0),(1,2)}
S2={(0,0),(1,2), (2,3),(3,5)}
● Si的构造
记S1i 是fi-1(X-wi)+pi的所有序偶的集合,则
S1i {( P,W ) | (P pi ,W wi ) S i1}
其中,Si-1是fi-1的所有序偶的集合
Si的构造:由Si-1和 S1i 按照支配规则合并而成。
支配规则:如果Si-1和S1i 之一有序偶(Pj,Wj),另一有(Pk,Wk),
5.5动态规划求解 0/1背包问题
1.问题描述 背包容量M,n个物品,分别具有效益值P1…Pn,物
品重量w1…wn,从n个物品中,选择若干物品放入 背包,物品要么整件放入背包,要么不放入。怎 样决策可以使装入背包的物品总效益值最大?
形式化描述:
目标函数:
约束条件:
max pixi
1i j
wixi M
1in
xi
0或1,
pi
0, wi
0,1
i
n
0/1背包问题:KNAP(1,n,M)
❖ 0/1背包问题:M=6,N=3,W=(3,3,4),P=(3,3,5) ❖ 贪心法:p3/w3 > p1/w1 > p2/w2 ❖ 贪心解 ∑P=5(0,0,1) ❖ 最优解是:∑P=6(1,1,0)
❖ 贪心法求解0/1背包问题不一定得到最优解! ❖ 动态规划求解的问题必须满足最优化原理
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

动态规划经典案例详解之背包问题【摘要】本文主要从动态规划经典案例——背包问题的动态规划设计思路出发,结合具体实例,对动态规划在程序设计中的典型应用以及衍生拓展进行详细分析。

【关键字】动态规划信息学奥赛0/1背包问题动态规划并非一个算法,而是一种解题的思路,其核心思想是通过使用大量的存储空间把中间结果记录下来,大大减少重复计算的时间,从而提高的程序的执行效率,因为信息学奥林匹克复赛题目的解决程序一般是有时间限制的,对于某些用搜索必然耗费大量时间的题目,动态规划几乎是唯一的选择。

但是动态规划并没有一个简单的模型可以套用,对于每个不同的题目都有对应的不同规划思路,我们只能通过对一些动态规划经典案例的学习来训练自己的动态规划思维能力,从而以不变应万变,应付各种复杂的程序设计,本文通过对动态规划经典案例之一的背包问题进行详细阐述,旨在让学生了解动态规划和搜索的不同设计思路以及动态规划的优越性。

【原型例题】从n个物品中选取装入背包的物品,每件物品i的重量为wi,价值为pi。

求使物品价值最高的选取方法。

【输入文件】第一行一个数c,为背包容量。

第二行一个数n,为物品数量第三行n个数,以空格间隔,为n个物品的重量第四行n个数,以空格间隔,为n个物品的价值【输出文件】能取得的最大价值。

【分析】初看这类问题,第一个想到的会是贪心,但是贪心法却无法保证一定能得到最优解,看以下实例:贪心准则1:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。

这种策略不能保证得到最优解。

例如,考虑n=2,w=[100,10,10],p=[20,15,15],c=105。

当利用价值贪婪准则时,获得的解为x=[1,0,0],这种方案的总价值为20。

而最优解为[0,1,1],其总价值为30。

贪心准则2:从剩下的物品中选择可装入背包的重量最小的物品。

虽然这种规则对于前面的例子能产生最优解,但在一般情况下则不一定能得到最优解。

考虑n=2,w=[10,20], p=[5,100],c=25。

当利用重量贪婪策略时,获得的解为x=[1,0],比最优解[0,1]要差。

贪心准则3:价值密度pi/wi贪婪算法,这种选择准则为:从剩余物品中选择可装入包的pi/wi值最大的物品,但是这种策略也不能保证得到最优解。

利用此策略解n=3,w=[20,15,15],p=[40,25,25],c=30时的得到的就不是最优解。

由以上的三种贪心策略可知,本题如果采用贪心方法求解,则完全取决于输入的数据,不管采用哪种方法都不能保证完全正确。

既然贪心不能解决,那么搜索行不行呢?我们可以深度搜索每种取物方案,然后依次对比得到的最终结果,取最大值即可。

这个思路是正确的,结果也是可期的,但是时间代价是阶乘级的,当物品数量很多(N>10就已经需要很长时间了)时,所耗费的时间代价是巨大的,对于奥赛要求一秒钟内出解就根本不可能了,于是我们不得不想另外的思路,【新思路】要使物品价值最高,即p1*x1+p2*x1+...+pi*xi(其1<=i<=n,x取0或1,取1表示选取物品i)取得最大值。

在该问题中需要决定x1..xn的值。

假设按i=1,2,...,n的次序来确定xi的值。

如果置x1=0,则问题转变为相对于其余物品(即物品2,3,.,n),背包容量仍为c的背包问题。

若置x1=1,问题就变为关于最大背包容量为c-w1的问题。

现设r={c,c-w1}为剩余的背包容量。

在第一次决策之后,剩下的问题便是考虑背包容量为r时的决策。

不管x1是0或是1,[x2,.,xn]必须是第一次决策之后的一个最优方案。

也就是说在此问题中,最优决策序列由最优决策子序列组成。

这样就满足了动态规划的程序设计条件。

【动态规划思路】阶段i:在前i件物品中,选取若干件物品放入背包中;状态:在前i件物品中,选取若干件物品放入所剩空间为c的背包中的所能获得的最大价值;决策:第i件物品放或者不放;由此可以写出动态转移方程:用f[i,j]表示在前i件物品中选择若干件放在所剩空间为j的背包里所能获得的最大价值f[i,j]=max{f[i-1,j-wi]+pi(j>=wi),f[i-1,j]}这样,就可以自底向上地得出在前n件物品中取出若干件放进背包能获得的最大价值,也就是f[n,c]【算法伪代码】for i:=0to c do{i=0也就是没有物品时清零}f[0,i]:=0;for i:=1to n do{枚举n件物品}for j:=0to c do{枚举所有的装入情况}beginf[i,j]:=f[i-1,j];{先让本次装入结果等于上次结果}if(j>=w[i])and(f[i-1,j-w[i]]+p[i]>f[i,j]){如果能装第i件物品}then f[i,j]:=f[i-1,j-w[i]]+p[i];{且装入后价值变大则装入}end;writeln(f[n,c]);【输入文件】104514340102530【输出结果】下面列出所有的f[i,j]0000404040404040101010104050505050501010102540505050657510103040405055708080分析次结果,可以很清楚的了解整个程序的执行过程,最后的80就是本题的答案。

【实例1:开心的金明(NOIP2006普及组真题)】金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。

更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。

今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。

于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。

他还从因特网上查到了每件物品的价格(都是整数元)。

他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1...jk,则所求的总和为:v[j1]*w[j1]+..+v[jk]*w[jk]请你帮助金明设计一个满足要求的购物单。

【输入文件】输入的第1行,为两个正整数,用一个空格隔开:N m(其中N(<30000)表示总钱数,m(<25)为希望购买物品的个数。

)从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数v p(其中v表示该物品的价格(v≤10000),p表示该物品的重要度(1~5))【输出文件】输出只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。

【分析】掌握了背包原型题目,此题可以迎刃而解,只要把总钱数N元看成是背包容量,物品的价格看成是物品的重量,重要度看成价值即可直接套用背包原型程序。

【实例2:金明的预算方案(NOIP2006提高组真题)】【题目描述】金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。

更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。

今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:主件附件电脑打印机,扫描仪书柜图书书桌台灯,文具工作椅无如果要买归类为附件的物品,必须先买该附件所属的主件。

每个主件可以有0个、1个或2个附件。

附件不再有从属于自己的附件。

金明想买的东西很多,肯定会超过妈妈限定的N元。

于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。

他还从因特网上查到了每件物品的价格(都是10元的整数倍)。

他希望在不超过N 元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:v[j1]*w[j1]+v[j2]*w[j2]+…+v[jk]*w[jk]。

(其中*为乘号)请你帮助金明设计一个满足要求的购物单。

【输入格式】输入文件的第1行,为两个正整数,用一个空格隔开:N m其中N(<32000)表示总钱数,m(<60)为希望购买物品的个数。

)从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数v p q(其中v表示该物品的价格(v<10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。

如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)【输出格式】输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)。

【输入样例】100058002040051300514003050020【输出样例】2200【分析】本题跟上题非常类似,可以确认用背包问题可以解决,但是难度却大大高于上题,这里提供两个思路。

简单方案:对每一个物品做两种决策,取与不取。

如果取,满足两个条件:1.要么它是主件,要么它所属的主件已经在包里了。

2.放进去后的重要度与价格的成绩的总和要比没放进时的大。

这两个条件缺一不可的。

于是得到如下的动规方程:f[i,j]:=f[i-1,j];if(i为主件or i的主件在包中)and(f[i,j]<f[i,j-v]+v*w)then f[i,j]:=f[i,j-v]+v*w;这个方案看似简单,其实有个非常复杂的问题,就是后一个条件“i的主件在包中”的判断,因为动态规划有个固有的弱点,就是很难知道整个中间过程,所以这个判断其实写起来是非常麻烦的。

下面提供一个更好的方案:改进方案:细细的看题目,还一个很重要的条件我们还没用:“每个主件可以有0个,1个或2个附件”。

也就是说对于一套物品(包含主件,所有的附件),我们称为一个属类,对一个属类的物品的购买方法,有以下5种:1.一个都不买2.主件3.主件+附件14.主件+附件25.主件+附件1+附件2这五种购买方法也是唯一的五种方法,也就是说对一属类的物品,我们只有上述的5种购买方法。

于是我们很自然的就会想到把物品按物品的属类捆在一起考虑。

这样我们把物品的属类作为dp的状态。

可以得到如下的dp方程:f[i,j]=max{f[i-1,j];第1种情况f[i-1,j-v[i,0]]+v[i,0]*w[i,0];第2种情况f[i-1,j-v[i,0]-v[i,1]]+v[i,0]*w[i,0]+v[i,1]*w[i,1];第3种情况f[i-1,j-v[i,0]-v[i,2]]+v[i,0]*w[i,0]+v[i,2]*w[i,2];第4种情况f[i-1,j-v[i,0]-v[i,1]-v[i,2]]+v[i,0]*w[i,0]+v[i,1]*w[i,1]+v[i,2]*w[i,2];}第5种情况这种方法的DP效率大大提高,不过需要对输入数据进行重新处理,使之按属类重新编号。

相关文档
最新文档