今日研究分支限界算法,拿了王晓东老师的算法设计与分析教材。仔细读懂了书中算法和代码且找出了算法的些许错误,在我写的第一篇原创博客中和大家分享。
对于装载问题这个实例,老师首先找到了O(2^n)复杂度的算法找到最大装载问题的解,然后对这个算法进行类似剪枝的操作,使得算法更加优化。为了找到最优解对应的装载策略,对代码进行了改进,在搜索子集树中保存当前已构造出的子集树中的路径指针,从而可在结束搜索后向根结点回溯,从而构造出最优装载。
直接上代码:
#include”queue.h”
template<class Type>
class Qnode
{
//friend void enqueue(Queue<Qnode<Type>*>&q, Qnode<Type>*&qn,Qnode<Type>*&best,Type result,Type bestw,int i,int n,bool ch,int bestx[]);
//friend Type maxloading(Type a[],Type c, int n, int bestx[]);
public:
Qnode<Type>* parent;
bool chosen;
Type weigth;
};
template<class Type>
void enqueue(Queue<Qnode<Type>*>&q, Qnode<Type>*qn,Qnode<Type>*&best,Type result,Type bestw,int i,int n,bool ch,int bestx[])
{
if(i==(n-1))
{
if(result==bestw)
{
best=qn;
bestx[n-1]=ch;
}
}
else
{
Qnode<Type> *b=new Qnode<Type>;
b->parent=qn;
b->chosen=ch;
b->weigth=result;
q.InQueue(b);
}
}
template<class Type>
Type maxloading(Type a[],Type c, int n, int bestx[])
{
Queue<Qnode<Type>*> q;
q.InQueue(0);
Type result=0;
Type bestw=0;
Type remain=0;
int i=0;
Qnode<Type>* qn=0,*best;
for(int j=i+1;j<n;j++)
remain+=a[j];
while(1)
{
Type tmp=result+a[i];
if(tmp<=c)
{
if(tmp>bestw)
bestw=tmp;
enqueue(q,qn,best,tmp,bestw,i,n,true,bestx);
}
if(result+remain >= bestw)
enqueue(q,qn,best,result,bestw,i,n,false,bestx);
q.OutQueue(qn);
if(!qn)
{
if(q.IsEmpty())
break;
q.InQueue(0);
q.OutQueue(qn);
i++;
remain-=a[i];
}
result=qn->weigth;
}
for(int j=n-2;j>=0;j–)
{
bestx[j]=best->chosen;
best=best->parent;
}
return bestw;
}
代码是我根据王老师的描述自己实现的。队列也是自己实现的循环队列。其中有一点需要指出的便是,在函数maxloading中的在判断是不是要把右子树加入队列时,原书没有要那个等号,这在对于仅仅需要找出最优解(数值)的问题当中是没有问题的。但是为了找出最优装载策略,如果没有等号,则算法无法到达叶子结点处,从而无法找到best这个结点。更加无法构造出最优解。
改进方法:把大于改成大于等于即可