0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论

一、问题描述

0-1背包问题,部分背包问题。分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法。

二、算法原理

(1)0-1背包的DP算法

  0-1背包问题:有n件物品和一个容量为W的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。其中每种物品只有一件,可以选择放或者不放。

  最优子结构性质:对于0-1问题,考虑重量至多W的最值钱的一包东西。如果去掉其中一个物品j,余下的必是除j以外的n-1件物品中,可以带走的重量至多为W-wj的最值钱的一包东西。

  用子问题定义状态:令c[i,w]表示前i件物品恰放入一个容量为w的背包可以获得的最大价值。则其状态转移方程便是:

  在将前i件物品放入容量为w的背包中这个子问题,若只考虑第i件物品的策略,如果选择不放第i件物品,那么问题就转化为“前i-1件物品放入容量为w的背包中”,价值为c[i-1,w];如果选择放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为w-wi的背包中”,此时能获得的最大价值就是c [i-1,w-wi]再加上通过放入第i件物品获得的价值vi的和。按照这种思路进行递归,最后的能获得的最大价值即为c[n, W]。

(2)部分背包的贪心算法

  部分背包问题与0-1背包问题相似,不同点在于部分背包问题可以选择物品的一部分,而不是像0-1背包一样只能做二分选择。

部分背包问题同样具有最优子结构的性质。考虑如果从最优货物中去掉某物品j的重量w,则余下的货物必是可以从n-1件原有物品和物品j的wj-w中可带走的,重量至多为W-w的价值最大的一包东西。

  对于部分背包问题,可以使用贪心策略解决。首先对计算每件物品的单位价值,即vi/wi,然后按照贪心策略,在每次进行选择时优先选择单位价值高的物品。也就是说先选择当前单位价值最高的物品,如果拿完了该物品,并且仍然可以选取一些其他物品时,就再选取当前单位价值次高的物品,一直进行下去,直到不能再取为止。

(3)部分背包的DP算法

  部分背包问题也可以用DP算法解决。由于题设中已说明所有物品重量和价值均为整数,利用这一特点,可以巧妙的将部分背包问题转化为0-1背包问题,然后调用0-1背包问题的DP算法进行求解。

  转化方法是:把第i种物品拆成重量依次为1,2,4...2^(k-1),wi-2^k+1的物品,对应的价值则依次是单位价值乘以拆分重量所得结果。在拆分序列中k是满足wi -2^k+1>0的最大整数。例如,如果wi为14,就将这种物品分成系数分别为1,2,4,7的四件物品。这是二进制的思想,这种划分总可以表示该物品可以选择的所有重量值。通过这样的划分得到一个新的重量序列和价值序列,然后将新的重量序列和价值序列作为输入调用0-1背包算法即可解决部分背包问题。(详细思想可以参考背包九讲中的内容)

三、实验数据

(1)三个算法的实验数据输入均为:

  a)     物品的个数n

  b)     每个物品的价值v1,v2……vn

  c)     每个物品的重量w1,w2……wn

  d)     背包的最大重量W

(2)输出均为:

  当前选择的方案所能获得的最大价值

  在本实验对三个算法测试中,将取背包最大容量W为100,物品的个数n为5,所有物品组成的价值序列{v}为{60,100,120,80,90},重量序列{w}为{10,20,30,40,5}。将这些数据依次输入到各个算法中进行测试。

四、源代码

  代码太多了,附下载链接:http://download.csdn.net/detail/zhh1992/8359275

时间: 2024-10-22 16:36:46

0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论的相关文章

Redis源码分析(二十三)--- CRC循环冗余算法和RAND随机数算法

今天开始研究Redis源码中的一些工具类的代码实现,工具类在任何语言中,实现的算法原理应该都是一样的,所以可以借此机会学习一下一些比较经典的算法.比如说我今天看的Crc循环冗余校验算法和rand随机数产生算法. CRC算法全称循环冗余校验算法.CRC校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去.在接收端, 则根据信息码和CRC码之间所遵循的规则进

Hadoop Mapreduce 中的FileInputFormat类的文件切分算法和host选择算法

文件切分算法 文件切分算法主要用于确定InputSplit的个数以及每个InputSplit对应的数据段. FileInputFormat以文件为单位切分成InputSplit.对于每个文件,由以下三个属性值确定其对应的InputSplit的个数. goalSize:根据用户期望的InputSplit数据计算,即totalSize/numSplit.totalSize为文件总大小:numSplit为用户设定的Map Task个数,默认情况下是1. minSize:InputSplit的最小值,由

最小生成树:prim算法和kruskal算法

一个连通图的生成树是图的极小连通子图.它包含图中的所有顶点,并且只含尽可能少的边.若砍去它的一条边,就会使生成树变成非连通图:若给它增加一条边,则会形成一条回路. 最小生成树有如下性质: 1.最小生成树非唯一,可能有多个最小生成树: 2.最小生成树的边的权值之和总唯一,而且是最小的: 3.最小生成树的边数为顶点数减1. 构造最小生成树可以有多种算法.其中多数算法利用了最小生成树的下列一种简称为MST的性质: 假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集.若(u, v)是一条具有

java实现最小生成树的prim算法和kruskal算法

在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权值,若要以上图来构建最小生成树.结果应该如下所示: 这样构建的最小生成树的权值总和最小,为17 在构建最小生成树中,一般有两种算法,prim算法和kruskal算法 在prim算法中,通过加入最小邻接边的方法来建立最小生成树算法.首先构造一个零图,在选一个初始顶点加入到新集合中,然后分别在原先的顶点

动态规划之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

nyist oj 311 完全背包 (动态规划经典题)

完全背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是w.求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少.如果不能恰好装满背包,输出NO 输入 第一行: N 表示有多少组测试数据(N<7). 接下来每组测试数据的第一行有两个整数M,V. M表示物品种类的数目,V表示背包的总容

【动态规划】多重背包

贵有恒,何必三更起五更眠:最无益,莫过一日曝十日寒. [动态规划]多重背包 时间限制: 1 Sec  内存限制: 64 MB提交: 5  解决: 5[提交][状态][讨论版] 题目描述 张琪曼:“魔法石矿里每种魔法石的数量看起来是足够多,但其实每种魔法石的数量是有限的.” 李旭琳:“所以我们需要改变装包策略啦.” 现有N(N≤10)种魔法石和一个容量为V(0<V<200)的背包.第i种魔法石最多有n[i]件可用,每个占用的空间是c[i],价值是w[i].全部物品总数不超过50.求解将哪些魔法石

算法复习——背包dp

1.01背包 二维递推式子: 代码: for (i=1;i<=n;i++) for (x=m;x>=1;x--) if (x>=w[i]) f[i][x]=max(f[i-1][x-w[i]]+c[i],f[i-1][x]); else f[i][x]=f[i-1][x]; printf("%d",f[n][m]); // f(n,m)为最优解 return 0; 然而有时候,由于容量或者物品数过多可能导致用二维数组可能超空间,此时可以考虑一维的优化 用f[i]表示当

【动态规划】完全背包

完全背包与01背包的区别就是 01背包只有一次, 而完全背包有无限 我的01背包 完全背包 dp[i-1][j - k*weight[i]] +k*value[i]   经历了01背包,那么前面这个式子就很好理解了,k就代表无限个. 照例,先来一份最朴实无华的递推: int dp[maxn][maxn]; void fun(){ for(int i=0;i<n;i++){ for(int j=0;j<W;j++){ for(int k=0;k*w[i]<j;k++){ dp[i+1][j