三爪分区(动态编程示例)
Three prong partition (Dynamic Programming example)
我有一个 int
数组,其中包含像 {47, 94, 79, 90, 89, 14, 82, 92}
这样的数字。该数组必须分为三个子数组,以便每个数组的总和尽可能小,也就是最小。我认为它值得使用递归来解决,但是这种方法让我失望了,我也想过在初始数组上使用 qsort
然后将它除以 "greedily" 但它并不总是有效(例如取最低和最高数字等等)。
例如上面的数字将分为:
1) {94, 90, 14}
2) {92, 89}
3) {82, 79, 47}
此处第三个数组包含最高的最小和,即208
。数字的顺序无关紧要。问题是如何将数字公平地分成三组,使它们形成最小的总和。我必须测试所有可能性吗?
所描述的问题可以使用动态规划建模。我们可以定义一个状态space如下。
v[i,t1,t2] := minimal load in partition 3 attainable for items
in {0,...,i} where the total load in partition 1
is exactly t1 and the total load in t2 is exactly t2
if such a load exists and positive infinity otherwise
对于状态space,i
在{0,...n}
,t1
,t2
在{0,...,P}
,其中P
是项目的总和,它是 objective 值的上限,以 n*smax
为界,其中 smax
是输入中出现的最大值。
我们得到以下递归关系,其中案例基本上取决于迭代选择每个元素被分配到哪个分区,其中 s_i
表示第 i
个项目的大小。
v[i,t1,t2] = min { v[i-1,t1-s_i,t2],
v[i-1,t1,t2-s_i],
v[i-1,t1,t2] + s_i }
最小表达式中的第一项对应于将项目 i
分配到分区 3,第二种情况对应于将项目 i
分配到分区 2,第三种情况对应于分配项目 i
进入分区3,状态space被填充后,可以通过下面的表达式求值得到想要的结果(即分区的最小最大负载)
Result = min { max { t1, t2, v[n,t1,t2] : t1, t2 in {0,...,P} } }
上面的最大值表达式中,t1
对应分区1的负载,t2
对应分区2的负载,
状态值 v[n,t1,t2]
对应于分区 3 中的负载。草图算法的 运行 时间可以受到 O(n^3*smax)
的限制,这是一个伪多项式运行时限制。如果还需要将项目最佳分配到分区中,则必须使用回溯或辅助数据结构。
请注意,给其中一个相同的分区赋予特殊角色似乎是人为的,因为它的负载是状态的值,而其他分区的负载用于状态的轴 space。此外,乍一看,状态的值似乎很容易获得,因为它只是剩余的总负载
sum_{j=1}^{i} s_i - ( t1 + t2 )
但事实并非如此,因为上述数量仅在实际存在此类分配时才确定分区 3 中的负载;在状态space的定义中,使用正无穷表示不存在这样的赋值。
该方法与描述的方法非常相似here, page 12 ff. In total, the described problem can be seen as a scheduling problem, namely minimization of the makespan of 3 identical parallel machines. In the so-called three-field notation,问题表示为P3||Cmax
,这意味着机器数量不是输入的一部分,而是固定的。
我有一个 int
数组,其中包含像 {47, 94, 79, 90, 89, 14, 82, 92}
这样的数字。该数组必须分为三个子数组,以便每个数组的总和尽可能小,也就是最小。我认为它值得使用递归来解决,但是这种方法让我失望了,我也想过在初始数组上使用 qsort
然后将它除以 "greedily" 但它并不总是有效(例如取最低和最高数字等等)。
例如上面的数字将分为:
1) {94, 90, 14}
2) {92, 89}
3) {82, 79, 47}
此处第三个数组包含最高的最小和,即208
。数字的顺序无关紧要。问题是如何将数字公平地分成三组,使它们形成最小的总和。我必须测试所有可能性吗?
所描述的问题可以使用动态规划建模。我们可以定义一个状态space如下。
v[i,t1,t2] := minimal load in partition 3 attainable for items
in {0,...,i} where the total load in partition 1
is exactly t1 and the total load in t2 is exactly t2
if such a load exists and positive infinity otherwise
对于状态space,i
在{0,...n}
,t1
,t2
在{0,...,P}
,其中P
是项目的总和,它是 objective 值的上限,以 n*smax
为界,其中 smax
是输入中出现的最大值。
我们得到以下递归关系,其中案例基本上取决于迭代选择每个元素被分配到哪个分区,其中 s_i
表示第 i
个项目的大小。
v[i,t1,t2] = min { v[i-1,t1-s_i,t2],
v[i-1,t1,t2-s_i],
v[i-1,t1,t2] + s_i }
最小表达式中的第一项对应于将项目 i
分配到分区 3,第二种情况对应于将项目 i
分配到分区 2,第三种情况对应于分配项目 i
进入分区3,状态space被填充后,可以通过下面的表达式求值得到想要的结果(即分区的最小最大负载)
Result = min { max { t1, t2, v[n,t1,t2] : t1, t2 in {0,...,P} } }
上面的最大值表达式中,t1
对应分区1的负载,t2
对应分区2的负载,
状态值 v[n,t1,t2]
对应于分区 3 中的负载。草图算法的 运行 时间可以受到 O(n^3*smax)
的限制,这是一个伪多项式运行时限制。如果还需要将项目最佳分配到分区中,则必须使用回溯或辅助数据结构。
请注意,给其中一个相同的分区赋予特殊角色似乎是人为的,因为它的负载是状态的值,而其他分区的负载用于状态的轴 space。此外,乍一看,状态的值似乎很容易获得,因为它只是剩余的总负载
sum_{j=1}^{i} s_i - ( t1 + t2 )
但事实并非如此,因为上述数量仅在实际存在此类分配时才确定分区 3 中的负载;在状态space的定义中,使用正无穷表示不存在这样的赋值。
该方法与描述的方法非常相似here, page 12 ff. In total, the described problem can be seen as a scheduling problem, namely minimization of the makespan of 3 identical parallel machines. In the so-called three-field notation,问题表示为P3||Cmax
,这意味着机器数量不是输入的一部分,而是固定的。