需要从多组列表中获得最佳和组合的算法(逻辑)

时间:2012-01-18 06:57:28

标签: php algorithm logic sum combinations

我有多组数据,比如

第1组2,3,5,10,15
Group2 4,6,23,15,12
第3组23,34,12,1,5

我需要来自这3组的最佳总和(例如总和(g1 + g2 + g3)< = 25)

1st(g1)5 +(g2)15 +(g3)+ 5 = 25(最佳组合)

现在,对于下一组合,不需要使用每个相应组的上述值

Group1 2,3, 5 ,10,15
Group2 4,6,23, 15 ,12
Group3 23,34,12,1, 5

第二(g1)2 +(g2)23 = 25(最佳组合)

Group1 2 ,3, 5 ,10,15
Group2 4,6, 23 15 ,12
Group3 23,34,12,1, 5

第3(g1)15 +(g2)6 +(g3)+ 1 = 22(最佳组合)

我希望这可能有点复杂。但我可能会更好地解决这个问题。

由于

2 个答案:

答案 0 :(得分:4)

这是NP-Hard问题。

sub-set sum减少了
子集和问题:给定多集S和数k:当且仅当S'的{​​{1}}的子集时才返回true 1}},总结为S

<强>减少
给定k形式的子集和问题的实例,在(S,k)形式创建此问题的实例,其中(G1,G2,...,Gn,k)是具有元素{{的单例组1}}来自Gii是我们正在寻找的数字。

<强>证明:
子集和 - &gt;这个问题:假设有S个子集k,那么通过选择每个组中的一个元素:S'={si_1,si_2,...,si_m},它们总和为k,因为每个{ {1}}仅包含元素si_1 + si_2 + ... + si_m = k
此问题 - &gt;子集和:这里有相同的想法,假设有一组单例组总和为Gi_1, Gi_2, ... , Gi_m,我们可以找出Gi中哪些元素需要得到所需的子集和si

<强>结论:
这个问题是NP-Hard,并且没有已知的多项式解。由于您所寻求的是NP-Hard问题的优化问题,因此您的优化问题也是NP-Hard。因此,获得最佳解决方案的最佳方法可能是指数级解决方案,例如蛮力:只检查所有可能性,并返回最佳匹配。

注意:

  • 从示例2看来,您不需要从每个元素中选择一个元素 group,但是如果不是,则最多选择每个组中的一个元素 案例 - 这个问题仍然是NP-Hard,但减少将是一个 有点难。
  • 我对维基百科的回答中的所有链接都是针对未来读者的,因为维基百科今天已脱机。如果您有兴趣,可以在谷歌上搜索这些条款并查看缓存页面。

编辑:指数解决方案示例[伪代码]:

注意它没有经过测试,但它背后的想法应该有效:只检查第一组的所有可能性,并递归k减少一组,所以最后 - 你耗尽所有可能的解决方案,并且从他们那里回报最好的。

S

答案 1 :(得分:0)

子集和问题具有伪多项式动态编程方法。我们可以将其映射到具有复杂度O(S*N)O(S)空格的此变体问题,其中S是最大总和(示例中为25),N为总数所有群体中的元素。

这种复杂性不依赖于组的总数,因此如果O(N^G)强力解决方案不会收敛到G>=10的高值,则更适合。但请注意,此算法不适用于S>=biginteger

简而言之,DP递归解决方案如下:

Sol(grp_i, S) = True      if(grp_i==1 && grp_i dataset has element S) // base case
              = True      if(Sol(grp_i-1, S)==True OR
                             there exists element 'e' in grp_i dataset
                             such that Sol(grp_i-1, S-e)==True)
              = False     otherwise   

一旦我们发现数据集是否可解,我们就可以回溯解决方案。

下面的Python程序:

def bestsum(data, maxsum):
  res = [0]*(maxsum+1)
  res[0] = []  # base case
  for group in data:
    new_res = list(res) # copy res
    for ele in group:
      for i in range(maxsum-ele+1):
        if res[i] != 0:
          new_res[i+ele] = list(res[i])
          new_res[i+ele].append(ele)
    res = new_res
  for i in range(maxsum, 0, -1):
    if res[i] != 0:
      return res[i]
      break
  return []

print bestsum( [[2,3,5,10,15], [4,6,23,15,12], [23,34,12,1,5]], 25)
print bestsum( [[2,3,10,15],   [4,6,23,12],    [23,34,12,1]],   25)
print bestsum( [[3,10,15],     [4,6,12],       [23,34,12,1]],   25)

输出:

~$ python2 subsetsum.py
[5, 15, 5]
[2, 23]
[12, 12]