`
wangqisen
  • 浏览: 46988 次
文章分类
社区版块
存档分类
最新评论

01背包问题之二

 
阅读更多

P02:完全背包问题

题目

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}

这跟01背包问题一样有O(N*V)个状态需要求解,但求解每个状态的时间已经不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度是超过O(VN)的。

将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是试图改进这个复杂度。

一个简单有效的优化

完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。

这个优化可以简单的O(N^2)地实现,一般都可以承受。另外,针对背包问题而言,比较不错的一种方法是:首先将费用大于V的物品去掉,然后使用类似计数排序的做法,计算出费用相同的物品中价值最高的是哪个,可以O(V+N)地完成这个优化。这个不太重要的过程就不给出伪代码了,希望你能独立思考写出伪代码或程序。

转化为01背包问题求解

既然01背包问题是最基本的背包问题,那么我们可以考虑把完全背包问题转化为01背包问题来解。最简单的想法是,考虑到第i种物品最多选V/c[i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题。这样完全没有改进基本思路的时间复杂度,但这毕竟给了我们将完全背包问题转化为01背包问题的思路:将一种物品拆成多件物品。

更高效的转化方法是:把第i种物品拆成费用为c[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足c[i]*2^k<=V。这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。这样把每种物品拆成O(log(V/c[i]))件物品,是一个很大的改进。

但我们有更优的O(VN)的算法。

O(VN)的算法

这个算法使用一维数组,先看伪代码:

fori=1..N

forv=0..V

f[v]=max{f[v],f[v-cost]+weight}

你会发现,这个伪代码与P01的伪代码只有v的循环次序不同而已。为什么这样一改就可行呢?首先想想为什么P01中要按照v=V..0的逆序来循环。这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

这个算法也可以以另外的思路得出。例如,基本思路中的状态转移方程可以等价地变形成这种形式:

f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

将这个方程用一维数组实现,便得到了上面的伪代码。

最后抽象出处理一件完全背包类物品的过程伪代码,以后会用到:

procedureCompletePack(cost,weight)

forv=cost..V

f[v]=max{f[v],f[v-cost]+weight}

总结

完全背包问题也是一个相当基础的背包问题,它有两个状态转移方程,分别在“基本思路”以及“O(VN)的算法“的小节中给出。希望你能够对这两个状态转移方程都仔细地体会,不仅记住,也要弄明白它们是怎么得出来的,最好能够自己想一种得到这些方程的方法。事实上,对每一道动态规划题目都思考其方程的意义以及如何得来,是加深对动态规划的理解、提高动态规划功力的好方法。

以上来自背包九讲。

我的代码如下:

特别需要注意的是,如果要求一定要恰好符合背包的容量v的要求,必须将f[0]=0,而f[1.....N]均为负无穷。如果不要求,可以使得所有的f[i]均置为0。

#include<iostream>
using namespace std;
#define NUMMAX 10000
int max(int i,int j);
int main(){
	int n,v,weight[NUMMAX],value[NUMMAX],f[NUMMAX],j=0,i=0;
	cin>>n>>v;
	for(i=1;i<NUMMAX;i++)
		f[i]=0;
	for(i=0;i<n;i++)
		cin>>weight[i]>>value[i];
	for(i=0;i<n;i++){
		for(j=0;j<=v;j++){
			if(j>=weight[i]){
				f[j]=max(f[j],f[j-weight[i]]+value[i]);
			}
		}
	}
	cout<<f[v];
}
int max(int i,int j){
	if(i>=j)
		return i;
	else 
		return j;
}


分享到:
评论

相关推荐

    01背包问题_01背包问题_

    课程作业,实现算法实践书后的例题,实现01背包问题

    实验五:01背包问题的回溯算法设计

    实验目的:0/1背包问题的回溯算法设计 实验原理:回溯算法设计。 实验要求:基本掌握回溯算法设计的原理方法。熟练掌握VC++中编程实现算法的常用技术和方法。 算法思想: 0-1背包问题:给定n种物品和一背包.物品i的...

    回溯法01背包

    回溯法解决01背包问题c语言.rar 已调通

    动态规划解决01背包问题

    01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,...

    分支限界法求01背包c语言

    分支限界法求01背包问题的解.rar c语言 已调通

    基础背包问题和01背包问题

    1)一个简化的背包问题:一个背包能装总重量为 tota1_m,现有 n 个物件,其重量分别为(W1、W2、…、Wn)。问能否从这 n 个物件中挑选若干个物件放入背包中,使其总重量正好为 T ?...3)01背包问题

    c语言实现动态规划求01背包问题

    用c语言实现的基于动态规划求解01背包问题,,其中2.txt中的内容为: 4 5 2 1 3 2 12 10 20 15

    01背包问题-Java-回溯法

    本程序是用Java开发的,使用回溯法解决01背包问题。程序比较易懂。输入分三行,第一行是物品数量N和背包容量C,第二行是物品重量数组,第三行是价值重量数组。然后输出最优解。

    经典遗传算法(SGA)解01背包问题的python代码实现

    经典遗传算法(SGA)解01背包问题的python代码实现,说明如下: 1.采用经典的二进制编码,选择算子为轮盘赌选择,交叉算子为两点交叉,变异算子为反转(单点)变异 2.可调的参数为:gen,pc,pm,popsize,n,w,c,W,M 3.两...

    01背包问题Python实现

    假设背包容量为C,有以下4类物品,每类物品对应的货物数量分别为j1,j2,j3,j4,每个货物的体积分别为:vk1(k1∈j1),vk2(k2∈j2),vk3(k3∈j3),vk4(k4∈j4),它们所对应的价值为uk1(k1∈j1),uk2(k2∈j2),uk3(k3∈j...

    背包问题 数学建模 背包问题 数学建模

    背包问题: 01背包问题 02: 完全背包问题 03: 多重背包问题 04: 混合三种背包问题 05: 二维费用的背包问题 06: 分组的背包问题 07: 有依赖的背包问题 08: 泛化物品 09: 背包问题问法的变化 11: 背包问题的搜索解法

    背包问题九讲2.0最新版

    《背包问题九讲》,dd_engi大神...目录:1、01背包问题;2、完全背包问题;3、多重背包问题;4、混合三种背包问题;5、二维费用背包问题;6、分组的背包问题;7、有依赖的背包问题;8、泛化物品;9、背包问题的变化;

    用贪心算法实现背包问题

    用贪心算法实现背包问题 集SSH框架,android,行业资讯,数据库,web开发,设计模式希望大家一起分享

    Acwing 01背包问题详细思路解法笔记

    Acwing 刷题笔记 2.01背包问题详细解析及优化方案详解。欢迎大家下载互相交流。

    01背包问题,既是实现最优的求解

    tf2=new TextField(25); tf3=new TextField(25); tf4=new TextField(5); tf5=new TextField(25); tf6=new TextField(5); tf7=new TextField(5); button=new Button("计算最优值");

    经典背包问题九讲.exe

    第一讲 01背包问题 这是最基本的背包问题,每个物品最多只能放一次。 第二讲 完全背包问题 第二个基本的背包问题模型,每种物品可以放无限多次。 第三讲 多重背包问题 每种物品有一个固定的次数上限。 第四讲 ...

    动态规划_01背包_01背包_C++_算法_背包_动态规划_

    C++动态规划实现01背包算法入门通过二维表的方式实现01背包的选取问题

    背包问题详解

    这里有9种背包问题的详解,包括01背包问题,完全背包问题,多重背包问题,混合三种背包问题,二维费用的背包问题,分组的背包问题,有依赖的背包问题,泛华物品,背包问题问法的变化。每种背包问题不仅有详细的讲解...

    背包问题详解(01背包,完全背包,多重背包,混合背包,二维费用背包……)

    背包问题详解 01背包,完全背包,多重背包,混合背包,二维费用背包,分级背包,泛化物品等等的分析思路,解题技巧,还有各种背包问题的题目解答。

    01背包问题动态规划.docx

    01背包问题动态规划 01背包问题是一个经典的动态规划问题,在给定一定容量的背包和一组物品的情况下,求出装入背包的物品组合,使得总价值最大。 以下是一个用动态规划解决01背包问题的C++代码示例: ```cpp #...

Global site tag (gtag.js) - Google Analytics