盒子堆栈 - 动态规划

3

我目前正在练习一些动态规划。 我遇到了“盒子堆栈”问题。
盒子被表示为:

struct Box{
    double h;
    double w;
    double d;
};

问题是创建一个最高的箱子堆栈,其中堆栈中的每个箱子都比上面的箱子更大(宽度和深度)。假设在这种情况下,箱子不能旋转。

我将箱子存储在一个std :: vector <Box>中。首先按宽度和深度进行稳定排序,以便每当我选择一个箱子时,我只需要向前搜索适合的下一个箱子。

这里是我的问题 - 这是最优的吗?
我猜每次选择一个箱子,我需要线性时间(O(n))来选择下一个可能的箱子。
是否有一种不同的方法来存储箱子,可能在时间复杂度方面更好?

当然,欢迎任何其他优化。


我的完整代码:

//Get index of next box that fits or -1 if none
int getP(std::vector<Box>& boxes, int n){
    double n_w = boxes[n].w;
    double n_d = boxes[n].d;
    for (int i=n-1; i >= 0; i--){
        if (n_w > boxes[i].w && n_d > boxes[i].d)
            return i;
    }
    return -1;
}

//Get highest possible stack.
double stackOfBoxes(std::vector<Box>& boxes, int n, Box* bottom){
    if (n == -1)
        return 0;
    if (bottom == NULL || (bottom->d > boxes[n].d && bottom->w > boxes[n].w))
        return max(stackOfBoxes(boxes, n-1, bottom),stackOfBoxes(boxes, getP(boxes,n), &boxes[n])+boxes[n].h);
    else
        return stackOfBoxes(boxes, n-1, bottom);
}


int main(){
    std::vector<Box> boxes = { {3,1,1},{5,2,2},{10,7,7} };
    std::stable_sort(boxes.begin(), boxes.end(), sortByW);
    std::stable_sort(boxes.begin(), boxes.end(), sortByD);

    cout << stackOfBoxes(boxes, 2, NULL) << endl;
}

在箱子叠放问题中,我知道箱子可以旋转(任何一面都可以作为底部)。你也是这样吗? - Nelfeal
@Nelxiost 这是一个有趣的案例,但现在让我们假设它们不能旋转。同时也编辑了帖子。 - A. Sarid
2个回答

2

这是我的问题——这个方案最优吗?

这是不正确的。

我使用了与您相同的输入测试了您的代码,除了第三个盒子的深度,我将其设为0.5

这里是结果。它给出15,而答案应该是10,因为没有其他盒子能够放在第三个盒子之上。


谢谢,我已经纠正了我的代码,请看下面我对@j_random_hacker的评论。 - A. Sarid

1
代码实际上是不正确的,因为您假设在不能必要地将当前(第n个)盒子包括在内时,子问题的最优解可以扩展。
例如:{2, 50, 1}, {1, 1, 2}, {1, 3, 3}

上面的例子在这两种排序下没有改变。您的算法getP(boxes, 3)将正确确定,第二个盒子{1, 1, 2}是最后一个可以放在最终{1, 3, 3}盒子之前的盒子,但是通过请求解决子问题stackOfBoxes(boxes, 1),调用代码假定列表中的任何一个盒子(即第一个或第二个盒子)都可以在最终的{1, 3, 3}盒子之前合法地放置——但事实并非如此。stackOfBoxes(boxes, 1)最终会正确返回2,只有使用第一个箱子才能达到这个结果,但外层的stackOfBoxes(boxes, 2)调用认为它可以将最终的{1, 3, 3}盒子堆叠在其上,尽管50>3。

它有助于非常清楚地了解stackOfBoxes(boxes, n)的返回值的含义。从您在此处编写代码的方式来看,它必须意味着“仅使用索引<= n处的盒子的任何有效堆栈(子序列)可实现的最大高度”。不幸的是,这个问题的表述并不能导致最优的子结构。(然而,存在其他可以做到这一点的表述。)
(感谢Nelxiost在我之前描述错误中发现一个漏洞!)

首先,感谢您的纠正和解释。我总是要跟踪底部框以便在将其添加到堆栈之前与当前的n框进行比较。我已经修正了我的代码,希望现在它可以涵盖所有情况。其次,我的问题主要是想找到是否有其他(更好的)方法来保存和搜索适合的下一个框。 - A. Sarid
我没有时间和精力去试图证明一个 bug 存在,但如果确实存在,您可以通过生成某个大小以下(例如最多 4 个盒子,所有四个维度都在 1..3 范围内)的所有可能情况,并将您的算法结果与已知良好的暴力算法进行比较来找到它。 如果您这样做,并编写一句英文句子,精确定义您认为“stackOfBoxes(boxes, n, bottom)”根据“n”和“bottom”返回什么(正如我在我的答案中所做的那样),我将继续查看此问题。 - j_random_hacker
1
还有一件事:你在原始代码或更新后的代码中实际上没有进行任何记忆化——实施起来只是“普通”的递归,这需要指数级的时间。 - j_random_hacker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接