【问题标题】:Dynamic programming: box stacking variation动态规划:盒子堆叠变化
【发布时间】:2021-08-05 02:00:12
【问题描述】:

我们有 n 个尺寸为 x、y、z(宽度、高度、深度)的框。 我们想在另一个里面插入最大数量的盒子。
如果内盒 (i) 的大小严格小于外盒 (j) 的大小,则可以将一个盒子放在另一个盒子里面:x[i] 这些框不能旋转,可以按任何顺序考虑。

如何通过动态规划实现目标?
这个问题类似于最长递增子序列问题吗?
按升序/降序排列盒子是否有意义?

【问题讨论】:

  • 到目前为止你有什么想法?
  • 按面积/体积排序可能会有帮助
  • 如果我们有 2D 框,我们可以按宽度排序,并在诱导的高度序列中找到最长的递增子序列,花费 n 个框的 O(n*log(n)) 时间。我不确定 3D 盒子是否可以实现这种时间复杂度。

标签: algorithm dynamic-programming


【解决方案1】:

对盒子进行拓扑排序,将它们排列成图如下: 每个盒子是图中的一个节点,从节点A到节点B的每条有向弧表示对应的盒子A持有盒子B。 扩充这个结构有一个无限大小的盒子和一个大小为零的盒子。

作为拓扑排序,该图将是一个有向无环图。因此,找到最长的路径不是 NP-hard,而是可以在 O(V+E) 中解决。两个扩充框之间的最长路径包含问题的答案。

设置排序是 O(V^2),从排序图中找到解决方案是 O(V+E),在这种情况下是 O(V^2),这是您的整体解决时间。

【讨论】:

    【解决方案2】:

    这是一个简单的 C++ 自上而下的方法:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <climits>
    
    using std::cin;
    using std::cout;
    using std::vector;
    using std::ostream;
    
    // G[i][j]==true if box i will fit inside box j.
    // L[i] is the number of boxes that will fit inside box i, or -1 if
    //      this value has not been determined.
    
    // Calculate how many boxes will fit inside box j.
    static int count(const vector<vector<bool>> &G,vector<int> &L,int j)
    {
        int n = L.size();
        int max_x = 0;
    
        for (int i=0; i!=n; ++i) {
            if (G[i][j]) {
                if (L[i]==-1) {
                    L[i] = count(G,L,i);
                }
                int x = L[i]+1;
                if (x>max_x) {
                    max_x = x;
                }
            }
        }
    
        return max_x;
    }
    
    
    int main()
    {
        int n; cin >> n;
        vector<int> x(n+1), y(n+1), z(n+1);
    
        for (int i=0; i!=n; ++i) {
            cin >> x[i] >> y[i] >> z[i];
        }
    
        // Add a huge box that contains any box
        x[n] = INT_MAX;
        y[n] = INT_MAX;
        z[n] = INT_MAX;
    
        vector<vector<bool> > G(n+1,vector<bool>(n+1,false));
    
        for (int i=0; i!=n+1; ++i) {
            for (int j=0; j!=n+1; ++j) {
                G[i][j] = x[i]<x[j] && y[i]<y[j] && z[i]<z[j];
            }
        }
    
        vector<int> L(n,-1);
    
        // Print the number of boxes that will fit in the huge box.
        cout << count(G,L,n) << "\n";
    }
    

    有多种方法可以加快速度,但这显示了允许使用动态编程的递归公式。

    【讨论】:

      猜你喜欢
      • 2016-12-26
      • 2017-06-23
      • 2017-05-12
      • 2023-03-20
      • 2015-03-24
      • 2018-06-11
      • 2018-02-25
      • 2013-11-29
      相关资源
      最近更新 更多