【发布时间】:2013-10-13 22:47:14
【问题描述】:
假设您有一组值 (1,1,1,12,12,16),您将如何生成所有可能的组合(不重复),其总和在预定义范围[min,max]。例如,以下是范围在13 和17 之间的所有组合(所有深度):
112
1112
11112
16
116
这假设相同值的每个项目是无法区分的,因此您在最终输出中没有1 12 的三个结果。蛮力是可能的,但在项目数量很大的情况下,所有深度的组合数量是天文数字。在上面的示例中,所有深度都有 (3 + 1) * (2 + 1) * (1 + 1) = 24 种组合。因此,总组合是任何给定值的项目数 + 1 的乘积。当然,我们可以在逻辑上抛出部分和大于最大值的大量组合(例如集合1612已经大于17 的最大值,因此请跳过其中包含16 和12 的任何组合。
我最初认为我可以将输入数组转换为两个数组并像里程表一样增加它们。但是我完全陷入了这种提前中断的递归算法上。有什么建议吗?
{
int uniqueValues = 3;
int[] maxCounts = new int[uniqueValues];
int[] values = new int[uniqueValues];
// easy code to bin the data, just hardcoding for example
maxCounts[0] = 3;
values[0] = 1;
maxCounts[1] = 2;
values[1] = 12;
maxCounts[2] = 1;
values[2] = 16;
GenerateCombinationsHelper(new List<int[]>(), 13, 17, 0, 0, maxCounts, new int[3], values);
}
private void GenerateCombinationsHelper(List<int[]> results, int min, int max, int currentValue, int index, int[] maxValues, int[] currentCombo, int[] values)
{
if (index >= maxValues.Length)
{
return;
}
while (currentCombo[index] < maxValues[index])
{
currentValue += values[index];
if (currentValue> max)
{
return;
}
currentCombo[index]++;
if (currentValue< min)
{
GenerateCombinationsHelper(results, min, max, currentValue, index + 1, maxValues, currentCombo, values);
}
else
{
results.Add((int[])currentCombo.Clone());
}
}
}
编辑
整数值仅用于演示。它可以是任何具有某种数值的对象(int、double、float 等...)
通常只有少数唯一值(约 10 个左右),但总共可能有数千个项目。
【问题讨论】:
-
那么,范围的顶部是独占的吗?如果不是,
{1,16}应该是有效的。 -
糟糕,我会解决的
-
你能假设所有的值都是正数吗?
-
是的,所有的值都是正数(显然非零)
-
最小值和最大值如何?有什么限制吗?如果不是,我认为下面的两个答案是正确的:)
标签: c# algorithm recursion combinatorics