序列中n个区间的最大总和

时间:2015-09-12 20:13:26

标签: algorithm dynamic-programming

我正在做一些编程“kata”,这是编程(和武术)的技能构建练习。我想学习如何在更短的时间内解决这些算法,所以我需要培养我对模式的了解。最终我想在越来越有效的时间复杂度(O(n),O(n ^ 2)等)中解决,但是现在我可以用任何效率来确定解决方案。

问题:

鉴于arr [10] = [4,5,0,2,5,6,4,0,3,5]

给定不同的段长度,例如一个3长度段和两个2长度段,找到段的最佳位置(或包含的最大总和),而不重叠段。

例如,此数组和这些段的解是2,因为:

{4 5} 0 2 {5 6 4} 0 {3 5}

在stackoverflow.com上发布之前我尝试过:

我读过:

Algorithm to find maximum coverage of non-overlapping sequences. (I.e., the Weighted Interval Scheduling Prob.)

algorithm to find longest non-overlapping sequences

我观看了麻省理工学院的开放式课程,并阅读了解决动态规划复杂问题的一般步骤,并完成了动态编程教程,用于通过记忆查找斐波那契数字。我以为我可以对这个问题进行记忆,但我还没有找到办法。

动态编程的主题是将问题分解为可以迭代以找到最佳解决方案的子问题。

我提出的(以OO方式)是

foreach (segment) {
    - find the greatest sum interval with length of this segment

这会产生不正确的结果,因为这些方法并不总是适合这种方法。例如:

鉴于arr [7] = [0,3,5,5,5,1,0]和两个3长度段,

第一段将花费5,5,5,第二段不留空间。理想情况下,我应该记住这个场景并再次尝试算法,这次避免使用5,5,5作为第一个选择。 这是正确的道路吗?

如何以“动态编程”方式处理此问题?

1 个答案:

答案 0 :(得分:0)

如果放置第一个分段,则会得到两个较小的子阵列:将其余两个分段中的一个或两个放入这些子阵列中的一个是与原始分段形状相同的子问题。 / p>

因此,这表示递归:放置第一个段,然后尝试将剩余段分配给子阵列的各种组合,并最大化这些组合。然后你记住:子问题都采用数组和段大小列表,就像原始问题一样。

我不确定这是最好的算法,但它是"直接"动态规划方法。

编辑:更详细:

评估函数的参数应该有两个部分:一个是表示被分析的子数组的一对数字(在本例中最初是[0,6]),第二个是表示多组数字的数字要分配的段的长度(在此示例中为{3,3})。然后在伪代码中你做这样的事情:

valuation( array_ends, the_segments):
    if sum of the_segments > array_ends[1] - array_ends[0]:
        return -infinity

    segment_length = length of chosen segment from the_segments
    remaining_segments = the_segments with chosen segment removed

    best_option = 0
    for segment_placement = array_ends[0] to array_ends[1] - segment_length:
         value1 = value of placing the chosen segment at segment_placement
         new_array1 = [array_ends[0],segment_placement]
         new_array2 = [segment_placement + segment_length,array_ends[1]]
         for each partition of remaining segments into seg1 and seg2:
             sub_value1 = valuation( new_array1, seg1)
             sub_value2 = valuation( new_array2, seg2)
             if value1 + sub_value1 + sub_value2 > best_option:
                  best_option = value1 + sub_value1 + sub_value2
    return best_option

此代码(以一个错误和拼写错误为模)计算估值值,但它使用相同的参数多次调用估值函数。因此,memoization的想法是缓存这些结果并避免重新遍历树的等效部分。所以我们可以通过包装评估函数来做到这一点:

memoized_valuation(args):
    if args in memo_dictionary:
         return memo_dictionary[args]
    else:
         result = valuation(args)
         memo_dictionary[args] = result
         return result

当然,您需要立即更改递归调用以致电memoized_valuation