问题描述:有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和最大。
设n个物品的重量和价值分别存储于数组w[ ]和v[ ]中,限制重量为tw。考虑一个n元组(x0,x1,…,xn-1),其中xi=0 表示第i个物品没有选取,而xi=1则表示第i个物品被选取。显然这个n元组等价于一个选择方案。用枚举法解决背包问题,需要枚举所有的选取方案,而根据上述方法,我们只要枚举所有的n元组,就可以得到问题的解。
显然,每个分量取值为0或1的n元组的个数共为2n个。而每个n元组其实对应了一个长度为n的二进制数,且这些二进制数的取值范围为0~2n-1。因此,如果把0~2n-1分别转化为相应的二进制数,则可以得到我们所需要的2n个n元组。
【算法】
maxv=0;
for (i=0;i<2n;i++)
{
}
设n件物品的重量分别为w0、w1、…、wn-1,物品的价值分别为v0、v1、…、vn-1。采用递归寻找物品的选择方案。设前面已有了多种选择的方案,并保留了其中总价值最大的方案于数组option[ ],该方案的总价值存于变量maxv。当前正在考察新方案,其物品选择情况保存于数组cop[ ]。假定当前方案已考虑了前i-1件物品,现在要考虑第i件物品;当前方案已包含的物品的重量之和为tw;至此,若其余物品都选择是可能的话,本方案能达到的总价值的期望值为tv。算法引入tv是当一旦当前方案的总价值的期望值也小于前面方案的总价值maxv时,继续考察当前方案变成无意义的工作,应终止当前方案,立即去考察下一个方案。因为当方案的总价值不比maxv大时,该方案不会被再考察,这同时保证函数后找到的方案一定会比前面的方案更好。
对于第i件物品的选择考虑有两种可能:
(1)
(2)
按以上思想写出递归算法如下:
try(物品i,当前选择已达到的重量和,本方案可能达到的总价值tv)
{
以当前方案作为临时最佳方案保存;
以当前方案作为临时最佳方案保存;
物品 | 0 | 1 | 2 | 3 |
重量 | 5 | 3 | 2 | 1 |
价值 | 4 | 4 | 3 | 1 |
并设限制重量为7。则按以上算法,下图表示找解过程。由图知,一旦找到一个解,算法就进一步找更好的佳。如能判定某个查找分支不会找到更好的解,算法不会在该分支继续查找,而是立即终止该分支,并去考察下一个分支。
Try(0,0,12) |
Try(1,5,12) |
Try(1,0,8) |
Try(2,5,8) |
Try(3,7,8) |
Try(2,3,8) |
Try(3,5,8) |
不能得到更好的解 |
不能得到更好的解 |
超重 |
不能得到更好的解 |
得到解:(1,0,1,0) maxv=7 |
得到解:(0,1,1,1) maxv=8 |
不能得到更好的解 |
超重 |
按上述算法编写函数和程序如下:
【程序】
# include
# define
double
int
struct
int
void find(int i,double tw,double tv)
{
}
}
void main()
{
}
【程序】
# include
# define
double
int
struct
int
struct
void next(int i,double tw,double tv)
{
}
double find(struct ele *a,int n)
{
}
void main()
{
printf(“输入各物品的重量和价值\n”);
for (k=0;k
}