堆叠和动态编程

时间:2017-02-06 15:24:03

标签: dynamic-programming combinatorics knapsack-problem

基本上我正试图解决这个问题:

给定N个单位立方体块,找到要使用所有块的较少数量的桩。桩是立方体或金字塔。例如,两个有效桩是使用64个块的立方体4 * 4 * 4 = 64,使用30个块的金字塔1 2 + 2 2 + 3 2 + 4 2 = 30。

然而,我无法找到接近它的正确角度。我觉得它类似于背包问题,但是,找不到实现。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

首先,我将给出一个递归关系,它将允许递归地解决问题。给定socket,让

N

分别是SQUARE-NUMS TRIANGLE-NUMS 中的方数和三角数的子集。让{1,...,N}成为这些的结合。请注意,PERMITTED_SIZES中出现1时,任何实例都是可行的,并产生非负最优值。

伪代码中的follwing函数将以递归方式解决问题中的问题。

PERMITTED_SIZES

我们的想法是为项目选择一个允许的bin大小,删除这些项目(这会使问题实例变小)并递归解决较小的实例。要使用动态编程来规避对同一子问题的多重评估,可以使用一维状态空间,即数组int MinimumNumberOfPiles(int N) { int Result = 1 + min { MinimumNumberOfPiles(N-i) } where i in PERMITTED_SIZES and i smaller than N; return Result; } ,其中A[N]是{{1}所需的最小堆数单位块。使用该状态空间,可以如下迭代地解决该问题。

A[i]

这初始化了事先已知的状态,并且对应于上述递归中的基本情况。接下来,使用以下循环填充缺失状态。

i

所需的最佳值将在for (int i = 0; i < N; i++) { if i is 0 set A[i] to 0, if i occurs in PERMITTED_SIZES, set A[i] to 1, set A[i] to positive infinity otherwise; } 中找到。请注意,此算法仅计算最小桩数,但不计算桩本身;如果需要合适的分区,则必须通过回溯或维护其他辅助数据结构来找到它。

总的来说,只要知道for (int i = 0; i <= N; i++) { if (A[i] is positive infinity) { A[i] = 1 + min { A[i-j] : j is in PERMITTED_SIZES and j is smaller than i } } } ,问题就可以通过A[N]步骤解决,因为PERMITTED_SIZES最多包含O(N^2)个值。

问题可以看作Rod Cutting Problem的改编,其中每个正方形或三角形大小的值为PERMITTED_SIZES,而其他每个大小的值都为N,目标是最小化总价值。

总的来说,从输入生成0需要额外的计算成本。

更确切地说,填充1后相应的桩的选择可以使用回溯生成如下。

PERMITTED_SIZES