实验指导书实验8分支限界法2.docx
《实验指导书实验8分支限界法2.docx》由会员分享,可在线阅读,更多相关《实验指导书实验8分支限界法2.docx(19页珍藏版)》请在冰豆网上搜索。
实验指导书实验8分支限界法2
算法设计与分析
实验指导书
(计算机科学与技术系)
编写
兰州交通大学电子与信息工程学院
2018年3月
实验7分支限界法-1
一、实验目的
(1)掌握分支限界法的各种不同的具体方法,包括队列式、改进的队列式以及优先队列式的区别。
(2)通过实验掌握分支限界法思想和方法;
(3)培养学生的动手能力。
二、实验仪器设备
(1)计算机;
(2)C++编译调试环境。
三、实验原理
掌握将算法转换为可运行程序的步骤。
四、实验内容及注意事项
(1)装载问题。
五、实验步骤
5.1装载问题
1)最基本的队列式分支限界法。
只计算最优值,没有计算最优解。
#include"stdafx.h"
#include
#include
#include
usingnamespacestd;
//子函数,将当前活节点加入队列
template
voidEnQueue(queue&Q,Typewt,Type&bestw,inti,intn)
{
if(i==n)//可行叶结点
{
if(wt>bestw)bestw=wt;
}
elseQ.push(wt);//非叶结点
}
//装载问题先尽量将第一艘船装满
//队列式分支限界法,返回最优载重量
template
TypeMaxLoading(Typew[],Typec,intn)
{
//初始化数据
queueQ;//保存活节点的队列
Q.push(-1);//-1的标志是标识分层
inti=1;//i表示当前扩展节点所在的层数
TypeEw=0;//Ew表示当前扩展节点的重量
Typebestw=0;//bestw表示当前最优载重量
//搜索子集空间树
while(true)
{
if(Ew+w[i]<=c)//检查左儿子
EnQueue(Q,Ew+w[i],bestw,i,n);//将左儿子添加到队列
//将右儿子添加到队列即表示不将当前货物装载在第一艘船
EnQueue(Q,Ew,bestw,i,n);
Ew=Q.front();Q.pop();//取下一个节点为扩展节点并将重量保存在Ew
if(Ew==-1)//检查是否到了同层结束
{
if(Q.empty())returnbestw;//遍历完毕,返回最优值
Q.push(-1);//添加分层标志
Ew=Q.front();Q.pop();//删除分层标志,进入下一层
i++;
}
}
returnbestw;
}
intmain(intargc,char*argv[])
{
intw[5]={0,1,2,3};
intc=5;
intn=3;
intbestp=MaxLoading(w,c,n);
cout<<"bestp="<return0;
}
2)改进的队列式分支限界法
加入了进入右子树的上界函数。
#include"stdafx.h"
#include
#include
#include
usingnamespacestd;
template
TypeMaxLoading(Typew[],Typec,intn)
{
//初始化数据
queueQ;//保存活节点的队列
Q.push(-1);//-1的标志是标识分层
inti=1;//i表示当前扩展节点所在的层数
TypeEw=0;//Ew表示当前扩展节点的重量
Typebestw=0;//bestw表示当前最优载重量
Typer=0;
for(intj=2;j<=n;j++)
r+=w[j];
//搜索子集空间树
while(true)
{
Typewt=Ew+w[i];
if(wt<=c){//检查左儿子
if(wt>bestw)bestw=wt;
if(i}
if(Ew+r>bestw&&iQ.push(Ew);
Ew=Q.front();Q.pop();//取下一个节点为扩展节点并将重量保存在Ew
if(Ew==-1)//检查是否到了同层结束
{
if(Q.empty())returnbestw;//遍历完毕,返回最优值
Q.push(-1);//添加分层标志
Ew=Q.front();Q.pop();//删除分层标志,进入下一层
i++;
r-=w[i];
}
}
}
intmain(intargc,char*argv[])
{
intw[5]={0,1,2,3};
intc=5;
intn=3;
intbestp=MaxLoading(w,c,n);
cout<<"bestp="<return0;
}
3)队列式分支限界法,包含最优解
#include"stdafx.h"
#include
usingnamespacestd;
template
classQueue
{
public:
Queue(intMaxQueueSize=50);
~Queue(){delete[]queue;}
boolIsEmpty()const{returnfront==rear;}
boolIsFull(){return(((rear+1)%MaxSize==front)?
1:
0);}
TTop()const;
TLast()const;
Queue&Add(constT&x);
Queue&AddLeft(constT&x);
Queue&Delete(T&x);
voidOutput(ostream&out)const;
intLength(){return(rear-front);}
private:
intfront;
intrear;
intMaxSize;
T*queue;
};
template
Queue:
:
Queue(intMaxQueueSize)
{
MaxSize=MaxQueueSize+1;
queue=newT[MaxSize];
front=rear=0;
}
template
TQueue:
:
Top()const
{
if(IsEmpty())
{
cout<<"queue:
noelement,no!
"<return0;
}
elsereturnqueue[(front+1)%MaxSize];
}
template
TQueue:
:
Last()const
{
if(IsEmpty())
{
cout<<"queue:
noelement"<return0;
}
elsereturnqueue[rear];
}
template
Queue&Queue:
:
Add(constT&x)
{
if(IsFull())cout<<"queue:
nomemory"<else
{
rear=(rear+1)%MaxSize;
queue[rear]=x;
}
return*this;
}
template
Queue&Queue:
:
AddLeft(constT&x)
{
if(IsFull())cout<<"queue:
nomemory"<else
{
front=(front+MaxSize-1)%MaxSize;
queue[(front+1)%MaxSize]=x;
}
return*this;
}
template
Queue&Queue:
:
Delete(T&x)
{
if(IsEmpty())cout<<"queue:
noelement(delete)"<else
{
front=(front+1)%MaxSize;
x=queue[front];
}
return*this;
}
template
voidQueue:
:
Output(ostream&out)const
{
for(inti=rear%MaxSize;i>=(front+1)%MaxSize;i--)
out<}
template
ostream&operator<<(ostream&out,constQueue&x)
{
x.Output(out);returnout;
}
constintN=3;
template
classQNode
{
public:
template
friendvoidEnQueue(Queue*>&Q,Typewt,inti,intn,Typebestw,QNode*E,QNode*&bestE,intbestx[],boolch);
template
friendTypeMaxLoading(Typew[],Typec,intn,intbestx[]);
public:
QNode*parent;//指向父节点的指针
boolLChild;//左儿子标识
Typeweight;//节点所相应的载重量
};
//将活节点加入到活节点队列Q中
template
voidEnQueue(Queue*>&Q,Typewt,inti,intn,Typebestw,QNode*E,QNode*&bestE,intbestx[],boolch)
{
if(i==n)//可行叶节点
{
if(wt==bestw)
{
//当前最优装载重量
bestE=E;
bestx[n]=ch;
}
return;
}
//非叶节点
QNode*b;
b=newQNode;
b->weight=wt;
b->parent=E;
b->LChild=ch;
Q.Add(b);
}
template
TypeMaxLoading(Typew[],Typec,intn,intbestx[])
{//队列式分支限界法,返回最优装载重量,bestx返回最优解
Queue*>Q;//活节点队列
Q.Add(0);//同层节点尾部标识
inti=1;//当前扩展节点所处的层
TypeEw=0,//扩展节点所相应的载重量
bestw=0,//当前最优装载重量
r=0;//剩余集装箱重量
intj;
for(j=2;j<=n;j++)
{
r+=w[j];
}
QNode*E=0,//当前扩展节点
*bestE=0;//当前最优扩展节点
while(true)
{
//检查左儿子节点
Typewt=Ew+w[i];
if(wt<=c)//可行节点
{
if(wt>bestw)
{
bestw=wt;
}
EnQueue(Q,wt,i,n,bestw,E,bestE,bestx,true);
}
//检查右儿子节点
if(Ew+r>bestw)
{
EnQueue(Q,Ew,i,n,bestw,E,bestE,bestx,false);
}
Q.Delete(E);//取下一扩展节点
if(!
E)//同层节点尾部
{
if(Q.IsEmpty())
{
break;
}
Q.Add(0);//同层节点尾部标识
Q.Delete(E);//取下一扩展节点
i++;//进入下一层
r-=w[i];//剩余集装箱重量
}
Ew=E->weight;//新扩展节点所对应的载重量
}
//构造当前最优解
for(j=n-1;j>0;j--)
{
bestx[j]=bestE->LChild;
bestE=bestE->parent;
}
returnbestw;
}
intmain()
{
floatc=5;
floatw[]={0,1,2,3};//下标从1开始
intx[N+1];
floatbestw;
cout<<"轮船载重为:
"<cout<<"待装物品的重量分别为:
"<inti;
for(i=1;i<=N;i++)
{
cout<}
cout<bestw=MaxLoading(w,c,N,x);
cout<<"分支限界选择结果为:
"<for(i=1;i<=N;i++)
{
cout<}
cout<cout<<"最优装载重量为:
"<system("pause");
return0;
}
4)优先队列式分支限界法,包含最优解。
#include"stdafx.h"
#include
#include
#include
#include
#include//vs2013greater模板需要包含这个头文件
usingnamespacestd;
constintN=4;
classbbnode;
template
classHeapNode
{
//去掉友元,学些阶段直接改public
public:
operatorType()const{returnuweight;}
template
friendbooloperator>(constHeapNode&n1,constHeapNode&n2)
{
returnn1.uweight}
public:
bbnode*ptr;//指向活节点在子集树中相应节点的指针
Typeuweight;//活节点优先级(上界)
intlevel;//活节点在子集树中所处的层序号
};
classbbnode
{//去掉友元
public:
bbnode*parent;//指向父节点的指针
boolLChild;//左儿子节点标识
};
//函数需要提前声明
template
voidAddLiveNode(bbnode*E,Typewt,boolch,intlev);
template
TypeMaxLoading(Typew[],Typec,intn,intbestx[]);
intmain()
{
floatc=70;
floatw[]={0,20,10,26,15};//下标从1开始
intx[N+1];
floatbestw;
cout<<"轮船载重为:
"<cout<<"待装物品的重量分别为:
"<for(inti=1;i<=N;i++)
{
cout<}
cout<bestw=MaxLoading(w,c,N,x);
cout<<"分支限界选择结果为:
"<for(inti=1;i<=4;i++)
{
cout<}
cout<cout<<"最优装载重量为:
"<system("pause");
return0;
}
priority_queue,vector>,greater>>H;
//将活节点加入到表示活节点优先队列的最大堆H中
template
voidAddLiveNode(bbnode*E,Typewt,boolch,intlev)
{
bbnode*b=newbbnode;
b->parent=E;
b->LChild=ch;
HeapNodeN;
N.uweight=wt;
N.level=lev;
N.ptr=b;
H.push(N);//H.Insert(N);
}
//优先队列式分支限界法,返回最优载重量,bestx返回最优解
template
TypeMaxLoading(Typew[],Typec,intn,intbestx[])
{
//定义剩余容量数组
Type*r=newType[n+1];
r[n]=0;
for(intj=n-1;j>0;j--)
{//第j层剩余集装箱的重量之和,比如w[]={0,20,10,26,15}
//则r[3]=15r[2]=41,r[1]=51,r[4]用不到
//以r[3]为例,表示在第3层,剩余集装箱的重量之和
r[j]=r[j+1]+w[j+1];
}
//初始化
inti=1;//当前扩展节点所处的层
bbnode*E=0;//当前扩展节点
TypeEw=0;//扩展节点所相应的载重量
//搜索子集空间树
while(i!
=n+1)//非叶子节点
{
//检查当前扩展节点的儿子节点
if(Ew+w[i]<=c)
{
cout<<"addingLevel"<
AddLiveNode(E,Ew+w[i]+r[i],true,i+1);
}
//右儿子节点
cout<<"addingLevel"<
AddLiveNode(E,Ew+r[i],false,i+1);
//取下一扩展节点
HeapNodeN;
N=H.top();H.pop();//H.DeleteMax(N);//非空
i=N.level;
E=N.ptr;
Ew=N.uweight-r[i-1];//N.uweight是上界,Ew是已经装入的,要减去剩余集装箱重量之和
cout<<"Level"<
}
//构造当前最优解
for(intj=n;j>0;j--)
{
bestx[j]=E->LChild;
E=E->parent;
}
delete[]r;
returnEw;
}
六、实验数据整理与结果分析
对各个算法的运行情况进行分析,根据复杂度分析所用计算机可接收的最大问题规模或者可在可接受时间内完成的问题的规模。
七、实验总结
在解空间树中进入遍历时,必须使用约束函数和限界函数进行剪枝以避免不必要的搜索。
八、实验报告
完成实验报告8。