【问题标题】:Balanced Partition greedy approach平衡分区贪心方法
【发布时间】:2017-03-06 23:20:13
【问题描述】:

我正在研究平衡分区问题herehere (problem 7)

问题基本上要求将给定的数字数组划分为 2 个子集(S1 和 S2),以便数字总和之间的绝对差为 S1 和 S2 |sum(S1) - sum(S2)| 需要最小。我不明白的一件事是为什么没有人建议贪婪的方法:

def balanced_partition(lst):
    idx = 0
    S1 = 0
    S2 = 0
    result_partition=[None]*len(lst)
    while idx < len(lst):
        new_S1 = S1 + lst[idx]
        new_S2 = S2 + lst[idx]
        if abs(new_S1 - S2) < abs(new_S2 - S1):
            result_partition[idx] = 1
            S1 = new_S1
        else:
            result_partition[idx] = 2
            S2 = new_S2
        idx += 1
    print("final sums s1 = {S1} and s2 = {S2} ".format(S1=S1, S2=S2))
    return result_partition

我的方法有什么问题?它似乎通过了我能想到的所有测试用例。

【问题讨论】:

  • “它似乎通过了大部分测试用例”。所以它失败了一些测试用例?这不能回答你的问题吗?
  • 对于大多数测试用例,我的意思是我找不到任何反对贪婪方法的论据,我自己也无法(提出)/找到负面测试用例。编辑了我的问题。
  • 您是如何搜索负面测试用例的?几乎每个排序列表都是您的最佳方法的反例(例如:[1,2,3])。
  • simple google search 没有帮助,我并没有真正想到排序大小写。
  • 我不认为你可以尝试太多——大多数未排序的列表也是反例。即使您只考虑长度为 3 的列表,[random.randrange(1000) for _ in xrange(3)] 大约是 1/3 的反例。

标签: algorithm dynamic-programming greedy


【解决方案1】:

简单的反例是[1,1,1,1,1,1,6]。贪心的方法会在两组之间传播,而最优解是[1,1,1,1,1,1],[6]

【讨论】:

    【解决方案2】:

    您的实施和方法没有任何问题。但是,如果您考虑这个特定问题中的所有子集,您可能会找到比贪婪输出更好的答案。即使在您共享的 wiki 页面中也有一些示例。

    您可能已经知道这两种方法之间的区别。虽然贪心算法总是会给你一个很好的结果,如此接近或可能等于最好的结果,但你必须考虑所有选项才能确定。动态编程方法以某种方式检查所有可能的子集。由于它保存了先前计算的子问题的结果,因此基本上比暴力破解要快。

    问题是何时使用贪婪或动态编程方法。我做过一些有竞争力的编程,当我看到一个 DP 问题(如分区、子集和、背包等问题)时,我有时会立即想出一个贪婪的解决方案,因为大多数时候它们更明显。人们在日常生活中一直使用贪婪的方法。在实施之前,我用示例测试我的算法,如果我说服自己这是正确的方法,我就会实施它。它在某种程度上有点直观。

    如果你找到一个应该有更好答案的测试用例,很可能这意味着你必须找到一个 DP 解决方案。如果你从评判系统获得了 WA,这意味着你没有找到好的测试用例,但没关系,你不必找到确切的测试用例,因为它不会帮助你找到更好的解决方案。

    【讨论】:

      猜你喜欢
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-07
      相关资源
      最近更新 更多