一連の値 ( 1
、1
、1
、12
、) があるとします。その合計が事前定義された範囲内にあるすべての可能な組み合わせ (反復なし) をどのように生成します12
か。たとえば、 と の間の範囲を持つ (すべての深さの) すべての組み合わせは次のとおりです。16
[min,max]
13
17
1
12
1
1
12
1
1
1
12
16
1
16
これは、同じ値の各項目が区別できないと想定しているため1
12
、最終出力に 3 つの結果はありません。総当たりは可能ですが、アイテム数が多い状況では、すべての深さでの組み合わせの数は天文学的です。上記の例では、(3 + 1) * (2 + 1) * (1 + 1) = 24 の組み合わせがすべての深さで存在します。したがって、組み合わせの合計は、任意の値の項目数 + 1 の積になります。もちろん、論理的には、部分和が最大値より大きい膨大な数の組み合わせを除外できます (たとえば、セット16
12
がすでに最大値より大きい)。の値な17
ので、 と が含まれる組み合わせはスキップ16
し12
てください)。
私は当初、入力配列を 2 つの配列に変換し、それらを走行距離計のようにインクリメントできると考えていました。しかし、私はこの再帰的アルゴリズムが早期に壊れてしまうことに完全に行き詰まっています。助言がありますか?
{
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 程度) ですが、合計で数千のアイテムが存在する場合があります。