わかりました、この問題は実際には線形シーケンスを中心に展開しています。最小値が 1 の場合、次のシーケンスを検討してください。
f(n) = 1 + 2 + ... + n - 1 + n
このようなシーケンスの合計は次のようになります。
f(n) = n * (n + 1) / 2
例として、n = 4 の場合、合計は 10 です。つまり、4 つの異なる数値を選択している場合、ゼロもマイナスも含まない最小合計は 10 です。逆に、合計が 10 で、 4 つの数字の場合、(1,2,3,4) の組み合わせは 1 つだけです。
したがって、最初に、合計が少なくともこの下限と同じかどうかを確認する必要があります。それ以下の場合、組み合わせはありません。等しい場合、正確に 1 つの組み合わせがあります。高いと複雑になります。
ここで、制約が合計 12 で 4 つの数字があるとします。f(4) = 10 であることがわかりました。しかし、最初の (最小の) 数値が 2 の場合はどうなるでしょうか?
2 + 3 + 4 + 5 = 14
したがって、最初の数は 1 より大きくすることはできません。最初の数はわかっています。ここで、合計 11 (12 - 1) の 3 つの数字のシーケンスを生成します。
1 + 2 + 3 = 6
2 + 3 + 4 = 9
3 + 4 + 5 = 12
2 番目の数値は 1 ではないため、2 でなければなりません。3 で始まる 3 つの数の最小和は 12 であり、11 を追加する必要があるため、3 になることはできません。
ここで、足し合わせると 9 (12 - 1 - 2) になる 2 つの数が見つかり、3 が可能な最小値になります。
3 + 4 = 7
4 + 5 = 9
3 番目の数字は 3 または 4 です。3 番目の数字が見つかると、最後の数字が固定されます。可能な組み合わせは次の 2 つです。
1, 2, 3, 6
1, 2, 4, 5
これを一般的なアルゴリズムに変えることができます。次の再帰的な実装を検討してください。
$all = all_sequences(14, 4);
echo "\nAll sequences:\n\n";
foreach ($all as $arr) {
echo implode(', ', $arr) . "\n";
}
function all_sequences($total, $num, $start = 1) {
if ($num == 1) {
return array($total);
}
$max = lowest_maximum($start, $num);
$limit = (int)(($total - $max) / $num) + $start;
$ret = array();
if ($num == 2) {
for ($i = $start; $i <= $limit; $i++) {
$ret[] = array($i, $total - $i);
}
} else {
for ($i = $start; $i <= $limit; $i++) {
$sub = all_sequences($total - $i, $num - 1, $i + 1);
foreach ($sub as $arr) {
array_unshift($arr, $i);
$ret[] = $arr;
}
}
}
return $ret;
}
function lowest_maximum($start, $num) {
return sum_linear($num) + ($start - 1) * $num;
}
function sum_linear($num) {
return ($num + 1) * $num / 2;
}
出力:
All sequences:
1, 2, 3, 8
1, 2, 4, 7
1, 2, 5, 6
1, 3, 4, 6
2, 3, 4, 5
これの 1 つの実装は、すべてのシーケンスを取得し、ランダムに 1 つを選択することです。これには、可能なすべての組み合わせを均等に重み付けするという利点があります。これは、あなたがしていることに有用または必要である場合とそうでない場合があります。
これは、合計が大きい場合や要素の数が多い場合には扱いにくくなります。その場合、上記のアルゴリズムを変更して、すべての値ではなく から$start
までの範囲のランダムな要素を返すことができ$limit
ます。