C / C ++实现类似于子集和的算法

时间:2010-01-28 07:56:31

标签: c++ c algorithm implementation knapsack-problem

问题比knapsack(或其类型,没有值,只有正权重)更简单。问题在于检查数字是否可以是其他数字的组合。该函数应返回truefalse

例如,

112且包含{ 17, 100, 101 }的列表应返回false469具有相同的列表应返回true35应返回false119应该返回true等等......

编辑:子集和问题比背包更准确。

4 个答案:

答案 0 :(得分:3)

这是子集和问题的特殊情况,其中集合仅包含一个负数(即表示112和{17,100,101}为{-112,17,100,101})。维基百科页面上有一些算法http://en.wikipedia.org/wiki/Subset_sum_problem

答案 1 :(得分:2)

一个可以帮助你的观察是,如果你的列表是{a,b,c ...}并且你要测试的数字是x,那么只有当x要么x时,x才能写成子列表的总和或者xa可以写成子列表{b,c,...}的总和。这使您可以编写一个非常简单的递归算法来解决问题。

编辑:这里有一些代码,考虑到下面的评论。未经测试,可能是马车;并不一定是最快的。但对于一个小型数据集,它可以很好地完成工作。

bool is_subset_sum(int x, std::list::const_iterator start, std::list::const_iterator end)
{
  // for a 1-element list {a} we just need to test a|x
  if (start == end) return (x % *start == 0); 

  // if x is small enough  we don't need to bother testing x - a
  if (x<a) return is_subset_sum (x, start+1, end);

  // the default case. Note that the shortcut properties of || means the process ends as soon as we get a positive.
  return (is_subset_sum (x, start+1, end) || is_subset_sum (x-a, start, end));
}

答案 2 :(得分:2)

请注意,当查询的数字变大时,正结果会变得更密集。例如,{17,100,101}可以生成大于100 ^ 2的所有数字。因此,最优算法可能取决于查询的数字是否远大于集合的成员。你可能会研究场论。

至少,如果该集合的最大公约数不在查询中,则您知道结果始终为false,并且可以在可忽略的时间内进行检查。

答案 3 :(得分:1)

如果要达到的数字不是太大,您可以生成该组中所有可到达的数字,这些数字都在[1,N]范围内。

问题:使用列表N中的元素覆盖L,其中N足够小,不用担心大小为N元素大小的向量。< / p>

算法:

  • 生成大小为V
  • 的向量N
  • 对于列表l中的每个元素L
    • 对于v中的每个可到达元素V
      • 将V中的所有元素v + n*l标记为可达