这个问题比knapsack
(或它的一种类型,没有值,只有正权重)更简单。问题在于检查一个数字是否可以是其他数字的组合。该函数应该返回true
or false
。
例如,
112 和一个应该返回的列表{ 17, 100, 101 }
,false
同469
一个列表应该返回true
,35
应该返回false
,119
应该返回true
,等等......
编辑:子集总和问题比背包更准确。
这个问题比knapsack
(或它的一种类型,没有值,只有正权重)更简单。问题在于检查一个数字是否可以是其他数字的组合。该函数应该返回true
or false
。
例如,
112 和一个应该返回的列表{ 17, 100, 101 }
,false
同469
一个列表应该返回true
,35
应该返回false
,119
应该返回true
,等等......
编辑:子集总和问题比背包更准确。
这是子集和问题的一个特例,集合只包含一个负数(即,将 112 和 { 17, 100, 101 } 表示为 { -112, 17, 100, 101 })。维基百科页面上有一些算法,http ://en.wikipedia.org/wiki/Subset_sum_problem 。
一个对您有帮助的观察是,如果您的列表是 {a, b, c...} 并且您要测试的数字是 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));
}
请注意,随着查询的数量变大,阳性结果会变得更密集。例如,所有大于 100^2 的数字都可以由 { 17, 100, 101 } 生成。所以最优算法可能取决于查询的数量是否远大于集合的成员。你可能会研究场论。
至少,如果集合的最大公约数不在查询中,您知道结果总是错误的,并且可以在可忽略不计的时间内进行检查。
如果要到达的数字不是太大,您可能可以从集合中生成所有可到达的数字,这些数字落在范围 [1,N] 内。
问题:N
使用 list 中的元素到达L
, whereN
足够小,不必担心 sizeN
元素大小的向量。
算法:
V
大小的向量N
l
对于列表中的每个元素L
v
对于每个可达元素V
v + n*l
将V 中的所有元素标记为可访问