Skip to content

最大装载

约 814 字大约 3 分钟

2024-11-03

思路

目标是尽可能装上最重的货物

解空间:集装箱重量数组的子集树

设定变量

  • 剩余集装箱重量
  • 轮船最大载重量
  • 当前最好的载重量
  • 当前的载重量
  • 当前层数
  • 记录当前方案
  • 最优方案

将剩余集装箱的重量初始化为所有集装箱的重量 (当前没有装载任何货物)

从树的第一层开始遍历,采用 根-左-右 的遍历方式

  • 对于一个将要处理的节点,如果当前层数大于集装箱总数,也就是到达树的叶子节点,判断当前的载重量是否大于最优载重量

    • 若大于,则更新最优载重量,并记录当前的解方案
  • 无论是不是最优解,结束递归

  • 对于一个将要处理的节点,现将剩余集装箱的重量减去当前集装箱的重量 (无论装不装当前集装箱,对于剩余的集装箱而言不会再包含当前集装箱)

  • 当前的载重量加上当前集装箱的重量没有超过轮船最大载重量,则将当前集装箱的重量加入当前载重量

    • 记录当前节点为进入左子树
    • 递归调用至下一层 (已经带着取当前集装箱的重量进入下一层,递归结束表示左子树已经遍历完成)
    • 回溯,即处理不取当前集装箱,当前载重量减去当前集装箱的重量
  • 当前的载重量加上剩余的集装箱重量小于最优的载重量,意味着这条分支已经没有意义 (剪枝,避免没有必要的遍历)。

  • 若存在更优的可能,递归调用层数加一,表示遍历右子树,并记录当前节点为进入右子树

  • 剩余载重量加上当前集装箱重量 (表示当前层左右子树遍历完成,回溯至上一层)

代码

static int n; // 集装箱数
static int[] w; // 集装箱重量数组
static int c; // 第一艘船的载重量
static int cw; // 当前载重量
static int bestW; // 当前最优载重量
static int r; // 剩余集装箱的载重量
static int[] x; // 当前的解
static int[] bestX; // 当前最优解
// 5-1
public static int maxLoading(int[] ww, int cc, int[] xx) {
    n = ww.length - 1;
    w = ww;
    c = cc;
    bestW = 0;
    x = new int[n + 1];
    bestX = xx;
    for (int i = 1; i <= n; i++) {
        r += w[i];
    }

    backtrack1(1);
    cw = 0;
    for (int i = 1; i <= n; i++) {
        r += w[i];
    }
//        backtrack2(1);
    return bestW;
}

public static void backtrack1(int i) {
    // 到达底部
    if (i > n) {
        if (cw > bestW) {
            for (int j = 1; j <= n; ++j) {
                bestX[j] = x[j];
            }
            bestW = cw;
        }
        return;
    }

    // 是否装入当前集装箱
    r -= w[i];
    if (cw + w[i] <= c) {
        cw += w[i];
        backtrack1(i + 1);
        cw -= w[i];
    }
    // 进入右子树
    if (cw + r > bestW) {
        backtrack1(i + 1);
    }
    r += w[i];
}

public static void backtrack2(int i) {
    // 到达底部
    if (i > n) {
        if (cw == bestW) {
            for (int j = 1; j <= n; ++j) {
                bestX[j] = x[j];
            }
        }
        return;
    }

    // 是否装入当前集装箱
    r -= w[i];
    if (cw + w[i] <= c) {
        x[i] = 1;
        cw += w[i];
        backtrack2(i + 1);
        cw -= w[i];
    }
    if (cw + r > bestW) {
        x[i] = 0;
        backtrack2(i + 1);
    }
    r += w[i];
}