问题比knapsack
(或其类型,没有值,只有正权重)更简单。问题在于检查数字是否可以是其他数字的组合。该函数应返回true
或false
。
例如,
112且包含{ 17, 100, 101 }
的列表应返回false
,469
具有相同的列表应返回true
,35
应返回false
,119
应该返回true
等等......
编辑:子集和问题比背包更准确。
答案 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 + n*l
标记为可达