装载问题
有一批共n个集装箱要装上2艘载重量分别为c1,c2的轮船,其中集装箱i的重量为wi,且要求确定是否有一个合理的装载方案可将这n个集装箱装上这2艘轮船。
可证明,采用如下策略可以得到一个最优装载方案:先尽可能的将第一艘船装满,其次将剩余的集装箱装到第二艘船上。
其实质是要求第一艘船的最优装载。 其解空间树是一棵子集树。
《算法设计与分析》-王晓东著 一书P159中给出的java算法是不完全正确的。自然语言表达中,已知具有n个元素输入的解空间树的层数是n+1。 其算法用n表示解空间树的层数,但在maxLoading算法的初始化阶段 有代码 n = w.length -1 (w的定义int[ ] w, 表示输入集装箱的重量数组),且解空间树层循环变量i 初始化为1 。若输入数组w 元素为3, 则此处初始化后n= 3-1 = 2; java数组的索引是从0开始的,故w[0]的数据不会被处理,只有i=1和i=2的两层数据会被处理,导致算法无法得到正确运行结果;
我对该算法的修订版本如下:
package ch06.book;
import java.util.LinkedList;
import java.util.Queue;
public class FIFOBBLoading {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] weight = {10,40,40};
int capacity = 50;
maxLoading(weight, capacity);
System.out.printf("the best load weight is: %d", bestWeight);
}
static int n;
static int bestWeight; // current max load;
static Queue queue; // queue for living nodes;
public static int maxLoading(int []containerWeight , int capacity) {
// initialization
n = containerWeight.length-1 ;
bestWeight = 0;
queue = new LinkedList();
queue.offer(new Integer(-1));
int i = 0; // represent the node level of current expand node;
int expandWeight = 0; // the weight of load at the expand node;
// search the binary solution space tree;
while (true) {
// check left child node;
System.out.printf("checking left child, trying weight:%d \r\n", expandWeight + containerWeight[i]);
if (expandWeight + containerWeight[i] <= capacity) {
// the overall weight include left child node is less than capacity,
// then put the left child node in queue;
System.out.printf("try put left child in queue, level %d \r\n", i);
enQueue(expandWeight + containerWeight[i], i);
}
// right child node is always feasible;
System.out.printf("try put right child in queue, level %d \r\n", i);
enQueue(expandWeight, i);
expandWeight = ((Integer)queue.poll()).intValue();
System.out.printf("pop out the first element at queue head, expandWeight: %d \r\n", expandWeight);
if (expandWeight == -1) {
// reach the end of nodes of same level;
if (queue.isEmpty())
return bestWeight;
queue.offer(new Integer(-1)); // add a mark node that represent the end of nodes of same level
System.out.println("add level end mark ");
expandWeight = ((Integer)queue.poll()).intValue();
System.out.printf("pop out the first element at queue head, expandWeight: %d, then go to next level \r\n", expandWeight);
i ++; // go to next level;
}
}
}
public static void enQueue(int currentWeight, int i) {
// put the living node into living node queue;
if (i == n) {
// this node is leaf node;
if (currentWeight > bestWeight) {
// found a better solution;
bestWeight = currentWeight;
System.out.printf("find current best load %d, node level is %d \r\n", bestWeight, i);
}
}
else {
// not leaf node;
queue.offer(new Integer(currentWeight));
System.out.println("DO put the child node in queue");
}
}
}
从main 方法的测试输入 weight = {10,40,40}, capacity = 50 ,可以求解出第一艘船最佳装载是50 , 与手动计算结果一致。
the best load weight is: 50