一、实验要求与内容
1.题目
有n个重量分别为{w1,w2,…,wn}的物品,它们的价值分别为{v1,v2,…,vn},给定一个容量为W的背包。设计从这些物品中选取一部分物品放入该背包的方案,每个物品要么选中要么不选中,要求选中的物品不仅能够放到背包中,而且具有最大的价值。
输入:三行。第一行输入两个数字n,m分别表示物品数量和背包容量;第二行输入n个数字表示n个物品的质量;第三行输入n个数字表示n个物品的价值。
输出:一行。表示背包的最大价值。
2.要求
(1)至少3种不同的算法求解0-1背包问题。
(2)设计尽可能多的测试数据;
(3)实验报告的内容必须包含:多种算法的详细设计、多种算法求解的测试结果、所采用的数据结构比较与分析、多种算法的比较与分析、创新之处、总结和体会、源程序代码与测试结果;
(4)实验报告可以参照平时的模板;
(5)提交的压缩包中包括:实验报告、每种算法的源程序(例如:.cpp文件);
二、多种算法的详细设计
1.穷举法
(1)设计思路
已知每个物品在解向量中的状态只有“放入”和“不放入”两种状态。因此可以使用二进制的0表示物品不放入背包,用二进制的1表示物品放入背包之中。穷举法则是基于对每个物品放入的可能性的预测,遍历所有的解向量,最终选择出放入背包中的物品价值最大的情况,也就是最优解。
(2)详细设计
Step1:进行数值输入,并在输入后计算2n,即需要穷举的次数;
Step2:使用循环从0到2n进行穷举;
Step3:在循环体中,先进行二进制转换,生成模拟解。根据模拟解计算模拟解对应的总重量是否超出背包总质量,若超出则进行下一轮循环;否则计算模拟解的总价值,并与已经出现的最大价值进行比较,记录较大值。
Step4:不断循环直到完成穷举;
2.动态规划法
(1)设计思路
利用二维数组存储本问题的最大价值。其中二维数组的每一行表示一个物品,二维数组的每一列表示背包从0递增的容量。将第一列和第一行的值初始赋值为0。后开始从第一个物品所在行(第1行)开始依次遍历。遍历内容为当背包容量为x时,是否将当前物品放入背包中。其是否放入的判断依据在于比较“不放入”和“放入”两种状态下哪一种的价值更高。直到完成遍历得出最大价值。
(2)详细设计
Step1:输入基础数据,对相应的数据结构进行初始化操作;
Step2:从value数组的(1,1)处开始向后遍历。当判断到某一节点时先判断当前节点的质量能否容纳该物品,若不能,继续后向遍历。若可以容纳则判断“不放入”和“放入”两种状态下哪一种的价值更高,特别注意的是当选择“放入”时要考虑到放入物品对背包质量的占用,从而需要判断剩余空间可容纳的价值与当前物品价值和与不放入时的价值哪一个更高。取较高的价值;
Step3:继续遍历,直到遍历完成,最优值出现在数组的右下角。
3.回溯法
(1)设计思路
以3个物品的情况为例。首先将1号物品放进背包里,判断其是否可以进入背包;接下来尝试把2号物品放入背包内,并判断其是否可以进入背包;接着考虑3号物品,并判断其是否可以进入背包;由于只有3件物品,并且对于每一种物品都已考虑过是否将其放入背包内,也就是找到了一种基本情况。找到一个基本情况后,计算包里的物品的总价值。每次找出一种满足条件的基本情况就进行一次回溯,找到最后放入包中的物品并将其取出,接着考虑是否放入编号在这个物品之后的第一个物品。这里我们就把1号物品取出,接下来考虑是否放入2号物品;类似上述过程,不断进行判断和回溯直到最后取出背包中的物品,算法结束。
(2)详细设计
Step1:输入基础数据,对相应的数据结构进行初始化操作;
Step2:尝试放入背包,计算并修改相关变量的数据;满足特定的条件后,进行后续回溯判断,直到回溯完成,获取最大值。
4.分支限界法
(1)设计思路
以限界函数为优先级。在根节点处没有任何物品被放入背包,背包载重的价值均为0,根据限界函数计算当前节点的目标价值。所谓目标价值也就是将0-1背包中的各项参数映射到背包问题中所得到的最优解。在节点1后生成节点2和3,分别表示当前物品放入和不放入背包,计算节点2和3的目标价值,并将其加入结点表,在节点表中取目标价值较大的节点优先进行搜索。当出现某节点是叶子结点,同时该结点的目标价值是节点表中的极大值时,该结点对应的解即是问题的最优解,搜索结束。
(2)详细设计
Step1:输入基础数据,并对数据进行预处理和排序(映射到背包问题计算目标价值),对相关变量进行初始化等操作;
Step2:从第1个节点开始计算价值上界,共需要遍历的空间树层数即为物品数量;
Step3:尝试放入第i个物品,更新最优值,添加新节点,并将其状态设置为未访问;从第i+1个节点计算价值上界,若能得到最优解,则添加节点带队列中;
Step4:取队列中价值上界最大的节点,从此节点往下计算最优解。
三、算法代码
1.穷举法
#include<stdio.h>
#include<math.h>
#define N 100
int goodsw[N];//Quality of items
int goodsv[N];//Value of items
int Bin[N]={
0}; //1 Put in the backpack, 0 means not in
int num; //num: Number of items;
int weight; //weight: maximum capacity of the backpack;
int time; //time:The number of cycles that are required
int valueMax=0;//The greatest value that has emerged
void Input(){
int i;
scanf("%d%d",&num,&weight);
time=(int)pow(2,num);
for(i=0;i<num;i++) scanf("%d",&goodsw[i]);
for(i=0;i<num;i++) scanf("%d",&goodsv[i]);
}
void ToBinary(int t){
//Items placed in a backpack are simulated in a decimal number of binary form
int j;
for(j=0;j<num;j++) Bin[j]=0;
j=num-1;
while(t!=0){
Bin[j--]=t%2;
t/=2;
}
}
void makeOpt(){
//Determine whether the current item is placed in the backpack
int cw,cv;
int i,flag=1;
cw=0;cv=0;
for(i=0;i<num;i++){
cw+=Bin[i]*goodsw[i];
if(cw>weight) {
flag=0;
break;
}
else cv+=Bin[i]*goodsv[i];
}
if((flag==1)&&(cv>valueMax)) valueMax=cv;
}
int main(){
int i;
Input();
for(i=