01背包问题实验报告.docx
《01背包问题实验报告.docx》由会员分享,可在线阅读,更多相关《01背包问题实验报告.docx(11页珍藏版)》请在冰豆网上搜索。
![01背包问题实验报告.docx](https://file1.bdocx.com/fileroot1/2023-1/28/1325906e-495e-4b01-b6c2-3c5c7fc2469a/1325906e-495e-4b01-b6c2-3c5c7fc2469a1.gif)
01背包问题实验报告
0-1背包问题实验报告
0-1背包问题实验报告小组成员:
姓名班级学号
贾倩楠201021130710211339
骆亮亮201021130710211318
高婧201021130810211370
一(算法设计名称:
0-1背包问题
二.实验内容
问题描述:
给定n种物品和一背包。
物品i的重量是w~其价值为v~背包ii的容量为C。
问应如何选择装入背包的物品~使得装入背包中物品的总价值最大?
在选择装入背包的物品时~对每种物品i只有两种选择~即装入背包或不装入背包。
不能将物品装入背包多次~也不能只装入部分的物品。
0-1背包问题是一个特殊的整数规划问题
nmaxvx,ii,1i
n,wx,C,,ii,,1i,x,{0,1},1,i,ni,
三.实验目的
1.运用动态规划思想~设计解决上述问题的算法~找出最大背包价值的装法。
2.掌握动态规划的应用。
四(算法:
问题求解思路
1.由0-1背包问题的最优子结构性质~建立计算m[i][j]的递归式如下:
j,wmax{m[i,1,j],m[i,1,j,w],v[i]},iim(i,j),,0,j,wm[i,1,j]i,
2.查找装入背包物品的函数:
从数组的最右下角开始寻找~如若m[i][weight]!
=
m[i-1][weight]~则该第i个物品就在背包中~将其从最大价值量中去掉~然后再接着寻找下一个在背包中的物品~直至i=0。
关键数据结构:
一个二维数组~两个一维数组~两个整型变量
intm[N+1][M+1]={0};//用于存储当前最好的价值量
intnumber,weight;//number表示物品的种类,weight表示背包重量的最大值
intw[N]={0},v[N]={0};//分别表示物品的重量和价值
函数摻块:
Main函数调用其余两个个函数完成算法:
voidknapsack(intnumber,intweight,int*w,int*v,intm[][M+1]);//整理背包函数,找出最大价值
voidfindobject(intnumber,intweight,int*w,int*v,intm[][M+1]);//找出所有在背包里的物品的函数
五(最终算法设计:
算法:
1.voidknapsack(intnumber,intweight,int*w,int*v,intm[][M+1]){//数组m[][],其横坐标row表示物品是第几个,纵坐标col表示当前背包中物品的重量从1到weight
introw,col;
for(row=1;row<=number;row++)
for(col=1;col<=weight;col++)
{
if(col>=w[row])//当背包重量大于第row个物品的重量时,再继续进行判断
{
-w[row]]+v[row]>m[row-1][col])if(m[row-1][col
m[row][col]=m[row-1][col-w[row]]+v[row];
else
1][col];//判断加入该第row个物品m[row][col]=m[row-
是否会增大价值量,若增大则加入,否则不加
}
else
m[row][col]=m[row-1][col];//如果背包重量小于w[row],则不加入任何物品,价值量不变
}
printf("Themostvalueoftheknapsackis:
%d.\n",m[number][weight]);//输出最大价值量
}
2.voidfindobject(intnumber,intweight,int*w,int*v,intm[][M+1]){
inti;
intx[N]={0};
for(i=number;i>0;i--)//从数组的最右下角开始找寻,直到找到最开始的m[0][]
{
if(m[i][weight]!
=m[i-1][weight])
{
x[i]=1;
weight=weight-w[i];//将找到的第i个物品从背包的重量中去掉
printf("%dthobjectischosen.weight:
%d,value:
%d\n",i,w[i],v[i]);//输出找到的物品的信息
}
}
}
六(运行结果:
当输入的数据不符合要求时:
七(分析时间复杂度:
n为物品总数~c为重量限制背包容量,
从m(i~j)的递归式容易看出~算法需要O(nc)计算时间。
当背
n包容量c很大时~算法需要的计算时间较多。
例如~当c>2时~算法
n需要Ω(n2)计算时间
八(改进算法:
算法思路:
1.由m(i,j)的递归式容易证明~在一般情况下~对每一个确定的i(1?
i?
n)~函数m(i,j)是关于变量j的阶梯状单调不减函数。
跳跃点是这一类函数的描述特征。
在一般情况下~函数m(i,j)由其全部跳跃点唯一确定。
如图所示。
对每一个确定的i(1?
i?
n)~用一个表p[i]存储其全部跳跃点。
初始时p[0]={(0~0)}~然后依次计算p[1],p[2]….p[n]
先将p[i]中可能包含的所有数对找出~然后再对其进行筛选~将不符合背包容量限制的~不符合最大价值量的数对删除~构成最终的p[i]跳跃点。
2.找背包中所装物品的方法和最初的算法类似~从最后装入的物品开始找起~若max与q[i].value[q[i].total-1]相等并且max不与q[i-1].value[q[i-1].total-1]相等~则说明第i个物品在背包中~输出相应的信息。
直至max=0。
数据类型:
structobject
{
intwei[N*2];
intvalue[N*2];
inttotal;
}p[20],q[20];//表示跳跃点集合的数据结构
intnumber,weight,max;//number表示物品的种类,weight表示背包重量的最大值,max表示装入背包最大的价值
intw[N]={0},v[N]={0};//分别表示物品的重量和价值
九(最终算法
1.voidknapsack(intnumber,intweight,int*w,int*v)
{//数组m[][],其横坐标row表示物品是第几个,纵坐标col表示当前背包中物品的重量从1到weight
inti,j,k,num;//i控制新的数据结构q的下标,j,k控制元素的比较,num控制结构q中各个数组元素的下标
intmax,all;//max表示最大价值
p[0].wei[0]=0;//将p[0],q[0]初始化为只含(0,0)的数据结构
p[0].value[0]=0;
p[0].total=1;
q[0].wei[0]=0;
q[0].value[0]=0;
q[0].total=1;
for(i=1;i<=number;i++)
{
p[i].total=q[i-1].total;
for(j=0;j{
p[i].wei[j]=q[i-1].wei[j];
p[i].value[j]=q[i-1].value[j];
}//将上个跳跃点的所有数对先复制下来
for(k=0;k{
if(q[i-1].wei[k]+w[i]<=weight)
{
p[i].wei[j]=q[i-1].wei[k]+w[i];
p[i].value[j]=q[i-1].value[k]+v[i];
p[i].total++;j++;
}//计算加入新的物品后的未超出限制重量的数对
}
//以上是计算每个跳跃点q[i]所含数对的个数并对其赋值
//之后是对q[i]目前的所有数对进行合并并删除,将其有序化
all=p[i].total;
for(num=0,j=0,k=p[i-1].total;j
{
if(p[i].wei[j]
{
if(p[i].value[j]<=p[i].value[k])
{
q[i].wei[num]=p[i].wei[j];
q[i].value[num]=p[i].value[j];
j++;num++;
}//总重量小并且价值小时,将其先放入q[i]中,num++
else
{
k++;p[i].total--;
}//总重量小单价值大时,将另一个删除,跳跃点所含数对数减1,再继续进行比较
}
elseif(p[i].wei[j]==p[i].wei[k])
{
if(p[i].value[j]
{
q[i].wei[num]=p[i].wei[k];
q[i].value[num]=p[i].value[k];//k价值大
}
else
{
q[i].wei[num]=p[i].wei[j];
q[i].value[num]=p[i].value[j];//j价值大
}
j++;k++;p[i].total--;num++;//总重量相等时,必定有个价值大的,将其写入p[i],另一个删除
}
else//j的总重量比k大时
{
if(p[i].value[j]>p[i].value[k])
{
q[i].wei[num]=p[i].wei[k];
q[i].value[num]=p[i].value[k];
k++;num++;
}//j的价值也比k大时,将k写入p[i],num++
else
{
j++;p[i].total--;
}//价值小的总重量大时,将其删除,再继续进行比较
}
}
q[i].total=p[i].total;
//下面将对剩余的没有排序的最后数对加入p[i]
while(j{
if(p[i].value[j]{
q[i].total--;
j++;
}//若j的价值比之前的最大的小。
则将其删除
else
{
q[i].wei[num]=p[i].wei[j];
q[i].value[num]=p[i].value[j];
j++;num++;
}//否则,将其加在之前填好p[i]的末尾
}
while(k{
if(p[i].value[k]{
q[i].total--;
k++;
}//若k的价值比之前的最大的小。
则将其删除
else
{
q[i].wei[num]=p[i].wei[k];
q[i].value[num]=p[i].value[k];
k++;num++;
}//否则,将其加在之前填好p[i]的末尾
}
}
max=q[i-1].value[q[i-1].total-1];
printf("Themostvalueoftheknapsackis:
%d.\n",max);//输出最大价值量
}
2.voidfindobject(intnumber,int*w,int*v){
inti,j;//控制循环
intmaxw,maxv;
maxw=q[number].wei[q[number].total-1];
maxv=q[number].value[q[number].total-1];
for(i=number;i>=0;i--)
{
for(j=q[i-1].total-1;j>=0;j--)
{
if((maxw-w[i])==q[i-1].wei[j]&&(maxv-v[i])==
q[i-1].value[j])
{//当某个物品所属行的最大价值量与之前的物品的不同时,该物品
即为装入包中物品
printf("%dthobjectischosen.
weight:
%d,value:
%d\n",i,w[i],v[i]);//输出找到的物品的信息
maxw=maxw-w[i];
maxv=maxv-v[i];//将去掉该物品后的最大价值量修改
break;
}
if(maxw==q[i-1].wei[j]&&maxv==q[i-1].value[j])
break;
}
}
}
十(运行结果
当输入的数据不符合要求时:
十一.分析时间复杂度
上述算法的主要计算量在于计算跳跃点集p[i](1?
i?
n)。
由于q[i+1]=p[i+1],(w~v)~故计算q[i+1]需要O(|p[i+1]|)计算时间。
ii
合并p[i+1]和q[i+1]并清除受控跳跃点也需要O(|p[i+1]|)计算时间。
从跳跃点集p[i]的定义可以看出~p[i]中的跳跃点相应于x,…,x的0/1赋值。
in
n-i+1因此~p[i]中跳跃点个数不超过2。
由此可见~算法计算跳跃
nn,,,,,nin,,O|p[i,1]|,O2,O2,,,,点集p[i]所花费的计算时间为,,,2,2ii,,,,
n从而~改进后算法的计算时间复杂性为O
(2)。
当所给物品的重量w(1?
i?
n)是整数时~|p[i]|?
c+1~(1?
i?
n)。
在这种情况下~改进后i
n算法的计算时间复杂性为O(min{nc,2})。