基本上我正试图解决这个问题:
给定N个单位立方体块,找到要使用所有块的较少数量的桩。桩是立方体或金字塔。例如,两个有效桩是使用64个块的立方体4 * 4 * 4 = 64,使用30个块的金字塔1 2 + 2 2 + 3 2 + 4 2 = 30。
然而,我无法找到接近它的正确角度。我觉得它类似于背包问题,但是,找不到实现。
非常感谢任何帮助!
答案 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