我有一个几乎排序值的数组,长28个元素。我需要找到与算法提供的目标值相加的一组值(或者如果找不到精确的和,则最接近的总和 目标值)。
我目前有一个简单的算法来完成这项工作,但并不总能找到最佳匹配。它在理想情况下使用一组特定的值,但我需要一个更强大,更准确的解决方案,可以处理更多种类的数据集。
算法必须用C语言编写,而不是用C ++编写,并且用于嵌入式系统,因此请记住这一点。
这是我目前的算法供参考。它从可用的最高值开始迭代。如果当前值小于目标总和,则将该值添加到输出并从目标总和中减去该值。重复此过程直到达到总和或用完值。它提出了一个几乎提升的排序列表。
//valuesOut will hold a bitmask of the values to be used (LSB representing array index 0, next bit index 1, etc)
void pickValues(long setTo, long* valuesOut)
{
signed char i = 27;//last index in array
long mask = 0x00000001;
(*valuesOut) = 0x00000000;
mask = mask<< i;//shift to ith bit
while(i>=0 && setTo > 0)//while more values needed and available
{
if(VALUES_ARRAY[i] <= setTo)
{
(*valuesOut)|= mask;//set ith bit
setTo = setTo - VALUES_ARRAY[i]._dword; //remove from remaining }
//decrement and iterate
mask = mask >> 1;
i--;
}
}
还有一些参数:
值数组可能近似排序升序,但无法强制执行,因此假设没有排序。实际上,也可能存在重复值。
数组很可能包含一组不能在其范围内创建每个总和的值。如果无法找到确切的总和,则算法应返回创建下一个最低总和的值。
答案 0 :(得分:7)
此问题称为子集求和问题,这是Knapsack problem的特例。维基百科是一些算法的良好起点。
答案 1 :(得分:6)
正如其他人所说,这与子集和问题的优化版本相同,即NP-Complete。
由于您提到内存不足并且可能使用近似解(基于您当前的解决方案),因此有多项式时间近似算法可用于求解子集和的优化版本。
例如,给定e> 0,有一个多项式时间算法,它使用O((n * logt)/ e)空间,(t是目标和,n是数组的大小),它给你一个子集,使得和z不小于比最优的1 /(1 + e)倍。
即如果最大子集和为y,则算法找到子集sum z,使得
z <= y <= (1+e)z
并使用空格O((n * logt)/ e)。
可在此处找到此类算法:http://www.cs.dartmouth.edu/~ac/Teach/CS105-Winter05/Notes/nanda-scribe-3.pdf
希望这有帮助。
答案 2 :(得分:1)
如果值相当小,则它是一个简单的动态编程(DP)。时间复杂度将是O(n *目标)和存储器要求O(目标)。如果这满足你,网上有很多DP教程。例如,这里讨论的第一个问题(使用couns)与您的问题非常相似(除了它们允许多次使用每个数字):
http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=dynProg
<强>更新强> 是的,正如其他人所说,这是一个背包问题的简单案例。