如何在最少数量的包裹中包装物品(具有不同的重量)?

时间:2015-08-28 07:57:12

标签: algorithm combinatorics

所以我有 N 项目的权重: w [1],w [2],.. w [N] ,还有几个包可以容纳重量 M

问题是:如何对项目进行分组,以便我能够所有使用最少个数量的包<?p>?

测试用例:

重量 w [i] = [40,6,4,42,8,43,4,3,19,30]的物品。

行李可以 M = 50。

可接受的答案:(40,6,4)(42,8)(43,4,3)(19,30)

2 个答案:

答案 0 :(得分:2)

您的问题是线性箱包装的特殊情况,其中重量都是非负的。 在这种特殊情况下,贪婪的First-Fit算法总能产生最佳解决方案。

&#34;证明&#34;在这些课堂笔记上给出的不正确: http://cs.nyu.edu/~yap/classes/funAlgo/05f/lect/l5.pdf

正如@Fede所指出的,如果我们重新排列示例的输入并应用First-Fit算法,我们会得到一个非最佳结果:

w [i] =(43,6,4,42,8,40,4,3,19,30),M = 50

FF产量(43,4),(4,42),(8,40),(4,3,19),(30)为5袋。

我会删除这个答案以避免不彻底检查的耻辱,但我希望这可以防止其他人陷入同样的​​陷阱。

答案 1 :(得分:2)

第一次适合贪婪并不能保证最佳包装。使用提供的样品,第一次贴合可以尝试将重量为43的物品与重量为6的物品包装在一起,然后生成的包装将不少于5个包装而不是4个。

动态编程可能是一个非常有效的解决方案,它可以利用为较小的项目集解决问题。我将在这里提出一个简单的回溯,如果性能不可接受,你可以稍后进行优化。

我对此的看法如下。您可以编写一个简单的递归,使用以下规则为每个项目分配包ID:

  • 第一项将始终位于包0中。
  • 任何其他项目只能在已启动的软件包中,或启动新软件包。
  • 包裹中物品的重量总和不能超过M

这样的事情会实现这套规则。

int[] FindBestPackageForItems(int[] weights, int N, int M) {
    // in the worst scenario, you'll have N packages
    int lowestNumberOfBags = N;
    int[] bestPacking = new int[N];
    for (int i = 0; i < N; i++)
        bestPacking[i] = i;
    int[] weightInEachBag = new int[N];
    int[] currentPacking = new int[N];
    currentPacking[0] = 0; // First item is always in package 0
    weightInEachBag[0] = weights[0];
    int currentItem = 1; // Item 0 is already in bag 0, the next item to pack will be the item 1
    int usedBags = 1; // The first bag is already used by the first item
    PutItemsInBags(weights, N, M, currentPacking, weightInEachBag, currentItem, usedBags, bestPacking, ref lowestNumberOfBags);
    return bestPacking;
}

void PutItemsInBags(int[] weights, int N, int M, int[] currentPacking, int[] weightInEachBag, int currentItem, int usedBags, int[] bestPacking, ref int lowestNumberOfBags) {
    if (currentItem == N) {
        assert(usedBags < lowestNumberOfBags);
        for (int i = 0; i < N; i++)
            bestPacking[i] = currentPacking[i];
        lowestNumberOfBags = usedBags;
    }
    else {
        for (int p = 0; p < min(usedBags + 1, lowestNumberOfBags); p++) {
            if (weightInEachBag[p] + weights[currentItem] <= M) {
                weightInEachBag[p] += weights[currentItem];
                currentPacking[currentItem] = p;
                PutItemsInBags(weights, N, M, currentPacking, weightInEachBag, currentItem+1, max(p, usedBags), bestPacking, ref lowestNumberOfBags);
                weightInEachBag[p] -= weights[currentItem];
            }
        }
    }
}