したがって、各ポイントで A または B から選択するため、2^N の選択肢があります。特定の例では、N がたまたま 3 である場合に 8 があります。議論のために、決定の各セットをビットパターンとして特徴付けることができます。
そのため、ブルート フォース アプローチではすべてのビット パターンを試します。
しかし、明らかなことは、最初の数ビットが生成する数値が大きすぎる場合、後続の可能性のあるテール ビットのすべてのグループも大きすぎる数値を生成するということです。したがって、おそらくそれをモデル化するためのより良い方法は、すでに限界を超えて成長している手足を歩くことを気にしない木です.
各ビットからテーブルの最後まで到達できる最大合計を計算することもできます。任意の時点で、現在の合計とこれから取得できる最大値が K 未満である場合、現在の場所からのすべてのサブツリーは、トラバーサルを必要とせずに受け入れられます。コメントで説明されているように、すべての組み合わせが許容されるケースは、この観察の特殊なケースです。
以下で Serge が指摘したように、関連する観察は、最小値を使用し、逆のロジックを使用して、トラバーサルなしでサブツリー全体をキャンセルすることです。
さらなる最適化の可能性は、加算が交換可能であるため、それぞれを同じようにシャッフルする限り、A と B の順序を変更しても効果がないという観察の背後にあります。したがって、最大値ができるだけ早く増加するか、最小値ができるだけゆっくりと増加するように努力して、トラバーサルから可能な限り早く終了するように努めることができます。実際には、絶対最大値と最小値 (いずれも計算済み) を K と比較するヒューリスティックを適用することをお勧めします。
その場合、再帰的な実装が最も簡単です。たとえば(Cで)
/* assume A, B and N are known globals */
unsigned int numberOfGoodArraysFromBit(
unsigned int bit,
unsigned int runningTotal,
unsigned int limit)
{
// have we ended up in an unacceptable subtree?
if(runningTotal > limit) return 0;
// have we reached the leaf node without at any
// point finding this subtree to be unacceptable?
if(bit >= N) return 1;
// maybe every subtree is acceptable?
if(runningTotal + MAXV[bit] <= limit)
{
return 1 << (N - bit);
}
// maybe no subtrees are acceptable?
if(runningTotal + MINV[bit] > limit)
{
return 0;
}
// if we can't prima facie judge the subtreees,
// we'll need specifically to evaluate them
return
numberOfGoodArraysFromBit(bit+1, runningTotal+A[bit], limit) +
numberOfGoodArraysFromBit(bit+1, runningTotal+B[bit], limit);
}
// work out the minimum and maximum values at each position
for(int i = 0; i < N; i++)
{
MAXV[i] = MAX(A[i], B[i]);
MINV[i] = MIN(A[i], B[i]);
}
// hence work out the cumulative totals from right to left
for(int i = N-2; i >= 0; i--)
{
MAXV[i] += MAXV[i+1];
MINV[i] += MINV[i+1];
}
// to kick it off
printf("Total valid combinations is %u", numberOfGoodArraysFromBit(0, 0, K));
私は即興で考えているだけです。より良い解決策が存在する可能性があります。