【问题标题】:How to get maximum height of piled boxes?如何获得堆积箱的最大高度?
【发布时间】:2021-01-21 09:27:08
【问题描述】:

20 组带有参数{height, length, width} 的框。 如果{length_of_first, width_of_first}小于或等于{length_of_second, width_of_second},则可以将一个盒子堆在另一个盒子上,即

length_of_first <= length_of_second && width_of_first <= width_of_second。 盒子可以在任何一侧旋转

BoxSizes rotateRight(const BoxSizes& box) {
    BoxSizes box_sizes(box);

    int height = box_sizes.height;
    int width = box_sizes.width;
    int length = box_sizes.length;

    box_sizes.length = width;
    box_sizes.height = length;
    box_sizes.width = height;

    return box_sizes;
}

BoxSizes rotateOnward(const BoxSizes& box) {
    BoxSizes box_sizes(box);

    int height = box_sizes.height;
    int width = box_sizes.width;
    int length = box_sizes.length;

    box_sizes.length = height;
    box_sizes.height = length;
    box_sizes.width = width;

    return box_sizes;
}

主要目标是获得最高的箱子堆。 不是强制使用所有盒子,但一个盒子只能使用一次! 例子。给定两个盒子:

{27, 24, 35},
{76, 36, 3}

我可以堆放两个盒子,但最好不要堆放它们,只取第二个并旋转它并获得76

我应该用什么方法来解决这个问题因为我不能使用暴力破解,因为我需要考虑每个盒子的3 旋转,所以我需要运行(3 + 1) ^ 20 案例(@987654330 @因为一个盒子可能不用)

【问题讨论】:

  • 也许我在这里错了,但我认为您可以在示例中将这两个框堆叠起来。首先将 {76, 36} 放在地上(高度 3),然后将 {27, 24} 放在顶部(高度 35)。然后总高度为 38。小于 76,因此您的解决方案实际上是正确的。但是这些盒子是“可堆积的”。

标签: algorithm dynamic-programming


【解决方案1】:

我的建议将是一种混合方法,它使用动态规划来生成桩高的上限,然后进行 A* 搜索以找到解决方案。

首先,让我们构建一个包含 60 个节点的图,表示刚刚将 20 个盒子中的一个放置在 3 个方向的每一个中。为空的一堆再添加一个。

如果 B 可以堆在 A 上,那么您的箭头是 A -> B。“可以堆”表示它符合您的打桩规则和以下额外规则。如果长度和宽度匹配,则只能将较短的堆放在较长的堆上。如果盒子尺寸相同,则强制执行任意顺序。

这些限制的原因是,如果有一个不遵循这些附加规则的有效答案,您可以重新排列框以找到一个相同的高度。所以我们只需要寻找遵循这些规则的安排。有了这些循环,我们的图表中就没有循环了。

接下来,通过简单的递归图搜索,对于每个有方向的框,我们可以找到可以在其上制作的最高堆,忽略重复规则。记录这 61 个高度。

这些高度高估了您可以建造多高的桩。但是我们并没有尝试强制执行关于从不重复使用盒子的规则。让我们用 A* 搜索来解决这个问题。

我们需要一个Priority Queue,它首先返回最大的优先级。 (最大堆会很好。)这样,我们的搜索就变成了下面的伪代码。

queue.add((max height on empty ground, 0, empty path))
while True: # loop condition terminates at end.
    (priority, height, path) = queue.pop()
    if priority = height:
        EXIT HERE, HEIGHT IS ANSWER AND PATH IS OPTIMAL PILING
    else:
        queue.add((height, height, path))
        for oriented box that can pile on last in path: # in graph above
            if box not in path:
                new_height = height + height of box
                queue.add((
                    new_height + max_height on orientation,
                    new_height,
                    path with orientation added))

这将做的是从一条空路径开始,将每个方向放入队列中,然后将贪婪地探索尝试第一次找到的最高桩,每当遇到重复框标准时回溯。我们获得的优先级将始终是最高桩的高度上限。高度是到目前为止这堆的高度。这就是为什么当我们找到一个实际高度与优先级匹配的堆时,这就是最好的答案。

【讨论】:

  • 谢谢,这对我有用!稍后我会附上工作代码
【解决方案2】:

正如“btilly”先生所说,我们应该从所有可能的盒子旋转中创建一个图表。

每个节点代表一个旋转的(或原始形状)框。

只有当第二个盒子可以堆在第一个盒子上时,节点之间的边才能存在。

那么,让我们介绍一个描述盒子形状的结构:

struct BoxSizes {
    int length{};
    int width{};
    int height{};
    int type{-1};
    int num_of_box{};

    BoxSizes(const BoxSizes&) = default;
    BoxSizes(const std::vector<int>& box, int type, int num_of_box) : length(box[0]), width(box[1]), height(box[2]), type(type), num_of_box(num_of_box) {}
    /*Some helpful methods*/

我们给出这样的盒子形状:

std::vector<std::vector<int>> box_sizes = {
            {269, 152, 375},
            {45, 8, 259},
            {37, 113, 98},
            {685, 40, 35}
};

让我们创建盒子的所有旋转:

std::vector<BoxSizes> all_rotated_box;

for (const auto& box_as_vector : box_sizes) {
     /*Don't pay attention on type and count*/
     const auto& box = BoxSizes(box_as_vector, type++, count);
     count += 3;
     all_rotated_box.emplace_back(box);
     all_rotated_box.emplace_back(rotateRight(box));
     all_rotated_box.emplace_back(rotateOnward(box));
}

/*Let's sort them!*/
std::sort(all_rotated_box.begin(), all_rotated_box.end());

那么,我们来介绍一个结构Node

struct Node {
        int x, y, z;
        int type;
        Node() = default;
        Node(int _x, int _y, int _z, int type) : x(_x), y(_y), z(_z), type(type) {}
        bool operator==(Node a) {
            return (x == a.x) && (y == a.y);
        }
};

std::vector<Node> nodes;

/*From vector of boxes to vector of nodes*/
std::transform(all_rotated_box.begin(), all_rotated_box.end(), std::back_inserter(nodes),
                   [](const auto& box) { return  Node(box.length, box.width, box.height, box.type); });

让我们创建一个图表:

std::vector<std::vector<int>> Graph(nodes.size(), std::vector<int>(nodes.size(), 0));

    for (int i = 0; i < nodes.size(); i++) {
        auto x = nodes[i].x;
        auto y = nodes[i].y;
        auto type = nodes[i].type;

        for (int j = 0; j < nodes.size(); j++) {
            auto x_ = nodes[j].x;
            auto y_ = nodes[j].y;
            auto type_ = nodes[j].type;

            if(i == j) {
                Graph[i][j] = nodes[i].z;
            }

            if(type == type_ || (x == x_ && y == y_))
                continue;

            if((x < x_ || x <= x_) && (y < y_ || y <= y_) ||
               (x < y_ || x <= y_) && (y < x_ || y <= x_)) {
                Graph[i][j] = std::abs( nodes[j].z);
            }

        }
    }

所以,主循环是:

for(auto j = 0; j < nodes.size(); j++) {
        std::deque<int> q;

        q.push_back(j);

        std::vector<int> heighest(nodes.size(), 0);
        heighest[j] = Graph[j][j];

        while (!q.empty()) {
            std::vector<int> adjacent_nodes;

            auto curr{q.front()};
            q.pop_front();

            for (int i = 0; i < Graph[0].size(); i++) {
                if (Graph[curr][i] > 0 && i != curr) {
                    adjacent_nodes.push_back(i);
                }
            }

            for (auto node : adjacent_nodes) {
                heighest[node] = std::max(heighest[node], heighest[curr] + Graph[curr][node]);
                q.push_back(node);
            }
        }

        the_heighest = std::max(the_heighest, *std::max_element(heighest.begin(), heighest.end()));
    }

您可以在这里查看https://github.com/Ayrtat/codeforces/blob/master/BoxRight.cpp

【讨论】:

    猜你喜欢
    • 2018-06-23
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 2014-07-30
    • 2021-09-14
    • 1970-01-01
    相关资源
    最近更新 更多