// 17x2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
// 分支界定法:最大装载问题,改进版(使用FIFO)
#include<iostream.h>
#include "lqueue.h"
template<class T>
T GetMaxLoading(T w[], T c, int n)
{
LinkedQueue<T> Q;
// 为第一层初始化
Q.Add(-1);
int i = 1;
T Ew = 0, bestw = 0;
T r = 0; // 在E-节点时的剩余重量
// 初始化r,从货物2开始计算
for (int j = 2; j <= n; j++)
r += w[i];
while (true) {
// 测试左孩子
T wt = Ew + w[i]; // 左孩子的权重
if (wt <= c) { // 可行的左孩子
// 左孩子是x=1的情况,值会累计,比较大,因此会经常更新bestw,这样比每次无条件把右孩子加入队列要好
if (wt > bestw) bestw = wt;
// 提早改变bestw,用来给右子树做测试
if (i < n) Q.Add(wt); // 如果不是叶子,则添加到队列中
}
// 测试右孩子
// 如果当前节点的祖先的累计重量Ew+剩余物品的重量r,大于当前最优值,才放到队列里
// 也就是说,即使取了所有剩余物品的值也没用的话,当然不必把当前节点加入队列了
// 为什么不是i<=n?如果i=n就是到叶子层了,也就没有剩余重量了
// 无论是叶子层还是内层,首要的条件是Ew+r>bestw,否则没有意义。所以写成i<=n也没错
if (Ew + r > bestw && i < n)
Q.Add(Ew);
Q.Delete(Ew); // 取得下一个E-节点,删除Q队列的头元素,并放到Ew里。
if (Ew == -1) { // 当Ew=-1时,进入层的尾部,代表当前层的所有节点都处理完毕了
if (Q.IsEmpty()) return bestw;
Q.Add(-1); // 每次碰到-1标记进来,代表上一层所有的数据都处理完了,这时为下一层的尾部添加-1标记
Q.Delete(Ew); // 从队列中删除首个元素,同时取得下一个E-节点,准备下个循环使用
i++; // 前一层结束了,当然Ew的层编号i要加1
r -= w[i]; // 前一层结束了,代表着剩余重量要减去前一层的物品(第i件物品)
}
}
}
void main(void)
{
int w[6] = {0, 2, 2, 6, 5, 5};
int n = 5;
int c = 16;
cout << "Max loading is " << GetMaxLoading(w,c,n) << endl;
}