装载问题-分支限界法(队列式分支限界法,优先队列式分支限界法)
问题描述
有n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且
问题:
是否有一个合理的装载方案,可将这n个集装箱装上这2艘轮船?如果有,找出一种装载方案。
例如:当n=3, c1=c2=50
(1)若w=[10, 40, 40]
可将集装箱1和集装箱2装上第一艘轮船,而将集装箱3装上第二艘轮船;
(2)如果w=[20, 40, 40]
则无法将这3个集装箱都装上船;
队列式分支限界法
解装载问题的队列式分支限界法仅求出所要求的最优值,稍后进一步构造最优解。
首先检测当前扩展结点的左儿子结点是否为可行结点。如果是,则将其加入到活结点队列Q中。
然后,将其右儿子结点加入到活结点队列中(右儿子结点一定是可行结点)。2个儿子结点都产生后,当前扩展结点被舍弃。
活结点队列中,队首元素被取出作为当前扩展结点。
活结点队列已空,算法终止。
// QNode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include<queue>
using namespace std;
template<class Type>
class QNode
{
template<class Type>
friend Type MaxLoading(Type*, Type ,int, int*);
template<class Type>
friend void EnQueue(queue<QNode<Type>*>&, Type, int, int, Type, QNode<Type>*, QNode<Type>* &, int*, bool);
private:
QNode* parent;
bool LChind;
Type weight;
};
template<class Type>
void EnQueue(queue<QNode<Type>*>& Q, Type wt, int i, int n, Type bestw, QNode<Type>* E, QNode<Type>* &bestE, int* bestx, bool ch)
{
if (i == n)
{
if (wt == bestw)
{
bestE = E;
bestx[n] = ch;
}
return;
}
QNode<Type>* b;
b = new QNode<Type>;
b->weight = wt;
b->parent = E;
b->LChind = ch;
Q.push(b);
}
template<class Type>
Type MaxLoading(Type* w, Type c, int n, int* bestx)
{
queue<QNode<Type>*> Q;
Q.push(nullptr);
int i = 1;
Type cw = 0,
bestw = 0,
r = 0;
for (int i = 2; i <= n; i++)
r += w[i];
QNode<Type>* E = nullptr,
* bestE=nullptr;
while (true)
{
Type wt = cw + w[i];
if (wt < c)
{
if (wt > bestw)
bestw = wt;
EnQueue<Type>(Q, wt, i, n, bestw, E, bestE, bestx, true);
}
if(cw+r>=bestw)
EnQueue<Type>(Q, cw, i, n, bestw, E, bestE, bestx, false);
E = Q.front();
Q.pop();
if (!E)
{
if (Q.empty())
break;
Q.push(nullptr);
E = Q.front();
Q.pop();
i++;
r -= w[i];
}
cw = E->weight;
}
for (int j = n - 1; j > 0; j--)
{
bestx[j] = bestE->LChind;
bestE = bestE->parent;
}
for (int i = 1; i <= n; i++)
cout << bestx[i] << "\t";
cout << endl;
return bestw;
}
int main()
{
int w[4] = { 0,20,40,40 };
int c = 50;
int n = 3;
int* bestx = new int[4];
cout<<MaxLoading<int>(w, c, n, bestx)<<endl;
return 0;
}
优先队列式分支限界法
解装载问题的优先队列式分支限界法用最大优先队列存储活结点表。
活结点x在优先队列中的优先级定义为从根结点到结点x的路径所相应的载重量Ew(即:当前扩展结点船的载重量Ew)再加上剩余集装箱的重量r之和(即:将上界Ew+r定义为结点优先级)。
优先队列中优先级最大的活结点成为下一个扩展结点。
子集树中叶结点所相应的载重量与其优先级(上界值)相同,即:该叶子结点的上界值等于当前叶子结点处船的重量Ew。
在优先队列式分支限界法中,一旦有一个叶结点成为当前扩展结点,则可以断言该叶结点所相应的解即为最优解。此时可终止算法。
// LoadHeap.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include<queue>
using namespace std;
template<class Type>
class bbnode
{
template<class Type>
friend class Loading;
template<class Type>
friend class HeapNode;
private:
bbnode<Type>* parent;
bool LChild;
};
template<class Type>
class HeapNode
{
template<class Type>
friend class Loading;
public:
operator Type ()const { return uweight; }
private:
Type level,
uweight;
bbnode<Type>* ptr;
};
template<class Type>
class Loading
{
friend int main(void);
private:
Type MaxLoad();
void AddLiveNode(priority_queue<HeapNode<Type>>& H, Type lev, Type weight, bbnode<Type>* E, bool ch);
Type cw,//当前的重量
bestw,//最好重量
* w,//物品重量
c,//船的重量
n;
Type *r;
Type bestx[4];
};
template<class Type>
Type Loading<Type>::MaxLoad()
{
priority_queue<HeapNode<Type>> H;
bbnode<Type>* E = nullptr;
int t = 1;
cw = 0;
r = new Type[n + 1];
r[n] = 0;
for (int j = n - 1; j > 0; j--)
r[j] = r[j + 1] + w[j + 1];
while (t!=n+1)
{
if (cw + w[t] <= c)
AddLiveNode(H, t+1, cw + w[t] + r[t], E, true);
AddLiveNode(H, t+1, cw + r[t], E, false);
HeapNode<Type> N;
N = H.top();
H.pop();
E = N.ptr;
t = N.level;
cw = N.uweight - r[t-1];
}
for (int i = 3; i > 0; i--)
{
bestx[i] = E->LChild;
E = E->parent;
}
for (int i = 1; i <=n; i++)
{
cout << bestx[i] << "\t";
}
cout << endl;
return cw;
}
template<class Type>
void Loading<Type>::AddLiveNode(priority_queue<HeapNode<Type>>& H, Type lev, Type weight, bbnode<Type>* E, bool ch)
{
bbnode<Type> *b = new bbnode<Type>;
b->parent = E;
b->LChild = ch;
HeapNode<Type> N;
N.level = lev;
N.ptr = b;
N.uweight = weight;
H.push(N);
}
int main()
{
int w[] = {0,20,40,40};
Loading<int> load;
load.w = w;
load.c = 50;
load.n = 3;
cout<<load.MaxLoad()<<endl;
return 0;
}