堆栈的盒子-动态规划

Stack of Boxes - Dynamic Programming

本文关键字:动态规划 盒子 堆栈      更新时间:2023-10-16

我目前正在练习一些动态规划。我遇到了一堆箱子。
这些方框表示为:

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;
}

我的问题是——这是最优的吗?

不正确。

我用相同的输入尝试了你的代码,除了第三个框的深度,我做了0.5

结果如下。它给出了15,而答案应该是10,因为没有其他盒子可以放在第三个盒子的上面。

这段代码实际上是不正确的,因为您假设子问题的最优解可以扩展到包含当前(第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在我之前对bug的描述中发现了一个bug!)