下面有一组值。我需要知道的是,如果这些值的任何组合总和一定值(在这种情况下为46,134.77)。想出这个的最佳方法是什么?当然,手动操作需要数小时。
如果它返回true,我需要知道组合是什么。我可以在Excel VBA或C#应用程序中进行设置。什么都行不通。我不知道如何到达那里。
125.00 1,000.00 1,039.36 1,171.60 1,200.00 1,320.00 1,680.00 1,757.20 1,768.80 1,970.00 2,231.25 2,300.00 2,369.25 2,589.20 2,720.00 2,887.50 3,000.00 3,085.00 3,142.60 3,174.40 3,742.70 3,847.20 5,609.25 5,881.05 12,240.48 14,112.00 29,318.07 32,551.80
答案 0 :(得分:6)
正如paislee的答案中已经提到的,这是knapsack problem的变体。事实上,这个特定问题被称为subset sum problem,就像背包问题一样,它是NP完全的。
链接的维基百科页面显示了如何使用动态编程来解决问题,但请注意,由于其NP完整性,如果使整数列表过大,则总是很慢/不可能解决。
以下是一些更相关的SO问题:
答案 1 :(得分:3)
这几乎是一个有界knapsack problem,是history中研究得最多的计算问题之一。本地:
NP Complete 意味着您应该准备好编写一个巨型循环来总结每个(或几乎每个)数字组合。
我建议不要手工完成。几个小时是总低估。 这将花费你的一生。例如,从28人的游泳池中选择时,有超过4千万个14个数字的组合。(那只是14')。 p>
答案 2 :(得分:3)
您所描述的是Knapsack problem的变体。它的计算难度很难有效地解决,但对于一个小的集合,这是可行的。
此特定输入的确切数字组合为:
29,318.07 + 5,881.05 + 3,174.40 + 3,085.00 + 2,231.25 + 1,320.00 + 1,000.00 + 125.00
我使用以下Perl脚本来确定此解决方案:
sub knapsack {
my ($target, $path, @vals) = @_;
if ($target == 0) {
print "Got it: @$path\n";
exit;
}
while (my $val = pop @vals) {
next if $val > $target;
knapsack($target - $val, [@$path, $val], @vals);
}
}
knapsack(46134_77, [], (
125_00, 1000_00, 1039_36, 1171_60, 1200_00, 1320_00, 1680_00, 1757_20,
1768_80, 1970_00, 2231_25, 2300_00, 2369_25, 2589_20, 2720_00, 2887_50,
3000_00, 3085_00, 3142_60, 3174_40, 3742_70, 3847_20, 5609_25, 5881_05,
12240_48, 14112_00, 29318_07, 32551_80,
));
请注意,我已将您的十进制值转换为整数(通过将它们全部乘以100),因为浮点比较是一个雷区。 (有关详细信息,请参阅What Every Computer Scientist Should Know About Floating-Point Arithmetic。)
答案 3 :(得分:1)
首先阅读其他答案/评论。这是一个可用于小型数据集的解决方案。
double[] nums = new double[] { 10,20,30,40,50,60,70,80,90,100,150,200,250,300,400,500};
Parallel.ForEach(GetIndexes(nums.Length), list =>
{
if (list.Select(n => nums[n]).Sum()==350)
{
Console.WriteLine(list.Aggregate("", (s, n) => s += nums[n] + " "));
}
});
IEnumerable<IEnumerable<int>> GetIndexes(int count)
{
for (ulong l = 0; l < Math.Pow(2, count); l++)
{
List<int> list = new List<int>();
BitArray bits = new BitArray(BitConverter.GetBytes(l));
for (int i = 0; i < sizeof(ulong)*8; i++)
{
if (bits.Get(i)) list.Add(i);
}
yield return list;
}
}
答案 4 :(得分:0)
是的duskwuff是对的。唯一的组合,加起来为46134.77 就是这个:
125 1,000.00 1,320.00 2,231.25 3,085.00 3,174.40 5,881.05 29,318.07
花了2秒才发现。我使用过SumMatch Excel加载项。