回溯法和分支限界法解决01背包题教学文案Word文件下载.docx
- 文档编号:17407373
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:18
- 大小:131.81KB
回溯法和分支限界法解决01背包题教学文案Word文件下载.docx
《回溯法和分支限界法解决01背包题教学文案Word文件下载.docx》由会员分享,可在线阅读,更多相关《回溯法和分支限界法解决01背包题教学文案Word文件下载.docx(18页珍藏版)》请在冰豆网上搜索。
尽管这不是一个可行解,但可以证明其价值是最优值的上界。
因此,对于这个实例,最优值不超过22。
在实现时,由Bound计算当前节点处的上界。
类Knap的数据成员记录解空间树中的节点信息,以减少参数传递调用所需要的栈空间。
在解空间树的当前扩展节点处,仅要进入右子树时才计算上界Bound,以判断是否可将右子树剪去。
进入左子树时不需要计算上界,因为上界预期父节点的上界相同。
三、回溯法实现代码:
#include"
stdafx.h"
#include<
iostream>
usingnamespacestd;
template<
classTypew,classTypep>
classKnap
{
template<
friendTypepKnapsack(Typep[],Typew[],Typew,int);
private:
TypepBound(inti);
voidBacktrack(inti);
Typewc;
//背包容量
intn;
//物品数
Typew*w;
//物品重量数组
Typep*p;
//物品价值数组
Typewcw;
//当前重量
Typepcp;
//当前价值
Typepbestp;
//当前最后价值
};
TypepKnapsack(Typepp[],Typeww[],Typewc,intn);
template<
classType>
inlinevoidSwap(Type&
a,Type&
b);
voidBubbleSort(Typea[],intn);
intmain()
intn=4;
//物品数
intc=7;
//背包容量
intp[]={0,9,10,7,4};
//物品价值下标从1开始
intw[]={0,3,5,2,1};
//物品重量下标从1开始
cout<
<
"
背包容量为:
c<
endl;
cout<
物品重量和价值分别为:
for(inti=1;
i<
=n;
i++)
{
("
w[i]<
"
p[i]<
)"
;
}
背包能装下的最大价值为:
Knapsack(p,w,c,n)<
return0;
}
voidKnap<
Typew,Typep>
:
Backtrack(inti)
if(i>
n)//到达叶子节点
bestp=cp;
return;
if(cw+w[i]<
=c)//进入左子树
cw+=w[i];
cp+=p[i];
Backtrack(i+1);
cw-=w[i];
cp-=p[i];
if(Bound(i+1)>
bestp)//进入右子树
classTypew,classTypep>
TypepKnap<
Typew,Typep>
Bound(inti)//计算上界
Typewcleft=c-cw;
//剩余容量
Typepb=cp;
//以物品单位重量价值递减序装入物品
while(i<
=n&
&
w[i]<
=cleft)
cleft-=w[i];
b+=p[i];
i++;
//装满背包
if(i<
=n)
b+=p[i]/w[i]*cleft;
returnb;
classObject
friendTypepKnapsack(Typep[],Typew[],Typew,int);
public:
intoperator<
=(Objecta)const
return(d>
=a.d);
intID;
floatd;
TypepKnapsack(Typepp[],Typeww[],Typewc,intn)
//为Knap:
Backtrack初始化
TypewW=0;
TypepP=0;
Object*Q=newObject[n];
for(inti=1;
Q[i-1].ID=i;
Q[i-1].d=1.0*p[i]/w[i];
P+=p[i];
W+=w[i];
if(W<
=c)//装入所有物品
returnP;
//依物品单位重量价值排序
BubbleSort(Q,n);
Knap<
K;
K.p=newTypep[n+1];
K.w=newTypew[n+1];
K.p[i]=p[Q[i-1].ID];
K.w[i]=w[Q[i-1].ID];
K.cp=0;
K.cw=0;
K.c=c;
K.n=n;
K.bestp=0;
//回溯搜索
K.Backtrack
(1);
delete[]Q;
delete[]K.w;
delete[]K.p;
returnK.bestp;
voidBubbleSort(Typea[],intn)
//记录一次遍历中是否有元素的交换
boolexchange;
for(inti=0;
n-1;
i++)
exchange=false;
for(intj=i+1;
j<
=n-1;
j++)
if(a[j]<
=a[j-1])
Swap(a[j],a[j-1]);
exchange=true;
//如果这次遍历没有元素的交换,那么排序结束
if(false==exchange)
break;
b)
Typetemp=a;
a=b;
b=temp;
四、程序运行结果:
五、回溯法解决0-1背包问题复杂度分析:
计算上界需要O(n)时间,在最坏情况下有O(2^n)个右儿子节点需要计算上界,故解0-1背包问题的回溯算法所需要的计算时间为O(n2^n)。
方法2:
分支限界法:
一、分支限界法描述:
给定n种物品和一背包。
0,1≤i≤n.要求找一n元向量(x1,x2,…,xn,),xi∈{0,1},∋∑wixi≤c,且∑vixi达最大.即一个特殊的整数规划问题。
二、分支限界法步骤思想:
首先,要对输入数据进行预处理,将各物品依其单位重量价值从大到小进行排列。
在优先队列分支限界法中,节点的优先级由已装袋的物品价值加上剩下的最大单位重量价值的物品装满剩余容量的价值和。
算法首先检查当前扩展结点的左儿子结点的可行性。
如果该左儿子结点是可行结点,则将它加入到子集树和活结点优先队列中。
当前扩展结点的右儿子结点一定是可行结点,仅当右儿子结点满足上界约束时才将它加入子集树和活结点优先队列。
当扩展到叶节点时为问题的最优值。
0-1背包问题,当n=3时,w={16,15,15},p={45,25,25},c=30。
优先队列式分支限界法:
处理法则:
价值大者优先。
{}—>
{A}—>
{B,C}—>
{C,D,E}—>
{C,E}—>
{C,J,K}—>
{C}—>
{F,G}—>
{G,L,M}—>
{G,M}—>
{G}—>
{N,O}—>
{O}—>
{}。
三、分支限界法解决0-1背包问题实现代码:
//0-1背包问题分支限界法求解
MaxHeap.h"
friendTypepKnapsack(Typepp[],Typeww[],Typewc,intn,intbestx[]);
=(Objecta)const
returnd>
=a.d;
//单位重量价值
classKnap;
classbbnode
friendKnap<
int,int>
bbnode*parent;
//指向父节点的指针
boolLChild;
//左儿子节点标识
classHeapNode
operatorTypep()const
returnuprofit;
Typepuprofit,//节点的价值上界
profit;
//节点所相应的价值
Typewweight;
//节点所相应的重量
intlevel;
//活节点在子集树中所处的层序号
bbnode*ptr;
//指向活节点在子集中相应节点的指针
TypepMaxKnapsack();
MaxHeap<
HeapNode<
Typep,Typew>
>
*H;
voidAddLiveNode(Typepup,Typepcp,Typewcw,boolch,intlev);
bbnode*E;
//指向扩展节点的指针
Typew*w;
Typepcp;
int*bestx;
//最优解
intn=3;
intc=30;
intp[]={0,45,25,25};
intw[]={0,16,15,15};
intbestx[4];
//最优解
Knapsack(p,w,c,n,bestx)<
此背包问题最优解为:
bestx[i]<
"
Bound(inti)//计算节点所相应价值的上界
Typewcleft=c-cw;
//剩余容量高
//价值上界
//以物品单位重量价值递减序装填剩余容量
while(i<
=n&
w[i]<
=cleft)
//装填剩余容量装满背包
if(i<
=n)
b+=p[i]/w[i]*cleft;
returnb;
//将一个活节点插入到子集树和优先队列中
AddLiveNode(Typepup,Typepcp,Typewcw,boolch,intlev)
bbnode*b=newbbnode;
b->
parent=E;
LChild=ch;
HeapNode<
N;
N.uprofit=up;
N.profit=cp;
N.weight=cw;
N.level=lev;
N.ptr=b;
H->
Insert(N);
//优先队列式分支限界法,返回最大价值,bestx返回最优解
MaxKnapsack()
H=newMaxHeap<
(1000);
//为bestx分配存储空间
bestx=newint[n+1];
//初始化
inti=1;
E=0;
cw=cp=0;
Typepbestp=0;
//当前最优值
Typepup=Bound
(1);
//搜索子集空间树
while(i!
=n+1)
//检查当前扩展节点的左儿子节点
Typewwt=cw+w[i];
if(wt<
=c)//左儿子节点为可行节点
if(cp+p[i]>
bestp)
bestp=cp+p[i];
AddLiveNode(up,cp+p[i],cw+w[i],true,i+1);
up=Bound(i+1);
//检查当前扩展节点的右儿子节点
if(up>
=bestp)//右子树可能含有最优解
AddLiveNode(up,cp,cw,false,i+1);
//取下一扩展节点
DeleteMax(N);
E=N.ptr;
cw=N.weight;
cp=N.profit;
up=N.uprofit;
i=N.level;
//构造当前最优解
for(intj=n;
j>
0;
j--)
bestx[j]=E->
LChild;
E=E->
parent;
returncp;
//返回最大价值,bestx返回最优解
TypepKnapsack(Typepp[],Typeww[],Typewc,intn,intbestx[])
//装包物品重量
//装包物品价值
//定义依单位重量价值排序的物品数组
Object*Q=newObject[n];
//单位重量价值数组
Q[i-1].d=1.0*p[i]/w[i];
if(W<
=c)
//所有物品装包
//依单位价值重量排序
//创建类Knap的数据成员
K.cp=0;
//调用MaxKnapsack求问题的最优解
Typepbestp=K.MaxKnapsack();
for(intj=1;
bestx[Q[j-1].ID]=K.bestx[j];
deleteQ;
delete[]K.bestx;
returnbestp;
五、分支限界法解决0-1背包问题复杂度分析:
时间复杂度为:
O(2^n);
空间复杂度:
O(n2^n)。
六、回溯法与分支限界法分析比较:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 回溯 分支 限界 解决 01 背包 教学 文案