あなたの質問は、繰り返し数が受け入れられる回答を示しているようであり、加数を順序付けることができるすべての可能な方法を生成したくない. それを踏まえて回答します。
これを C++ で実装します。データ構造として、おそらく次のようなものを使用します。
struct partial_sum {
int min_last_summand;
std::vector< std::pair<partial_sum*, int> > prefixes;
};
std::map<int, partial_sum*> m;
ここで中心的な部分はマップm
です。合計の値を、それを取得する方法に関する情報にマップします。0
にマップして初期化しNULL
ます。メンバーは、特定の合計を取得するために考えられるすべてのprefixes
方法に関するデータを格納します。各ペアの最初の部分は、最後の部分を除くすべての被加数に関する情報へのポインターを提供し、2 番目の部分は最後のメンバーを提供します。これにより、有向非巡回グラフの形式が得られます。合計は多くの合計の接頭辞になる可能性があり、合計はさまざまな接頭辞を持つことができますが、すべての接頭辞の合計の値は現在の合計の値よりも小さくなります。
中央の反復ステップでは、 から最小限のエルケメントを削除しm
、入力セットから削除したばかりの値に要素を追加できるすべての可能な方法を生成します。したがって、新しい合計に新しいエントリを挿入する必要があるかどうかをマップで確認します。prefixes
また、既存のエントリと新しいエントリの両方について、マップから削除したポインタを最初の部分として、最後に追加した加数を 2 番目の部分として、リストに新しい項目を作成します。
すべての順列の生成を避けるために、加数の昇順 (またはむしろ非降順) で合計を生成するだけです。物事を簡単にするために、このmin_last_summand
情報を維持します。リスト内のペアのすべての 2 番目の要素の最小値が常に含まれている必要がありprefixes
ます。新しい合計を生成するとき、最後の被加数が接頭辞の最小の最後の被加数よりも小さい場合はスキップできます。また、合計値が目標の合計よりも大きい合計を生成しないようにすることもできます。
結果を印刷するときは、ターゲット合計から到達可能な DAG の部分を再帰し、そこから root までのすべてのパスをリストする必要がありますNULL
。したがって、各再帰ステップで、現在の部分合計へのポインターが得られます。そのポインターがNULL
の場合、被加数がゼロの合計を出力します。それ以外の場合は、すべてを反復処理しますprefixes
。各プレフィックスについて、そのプレフィックスを記述するすべての可能な方法を生成するために再帰しますがmin_last_summand
、最初の要素の が現在の最後の加数より大きくない場合、および 2 番目の要素がそれに続く加数より大きくない場合のみです。 . つまり、次の被加数を引数として再帰呼び出しに渡す必要があります。まとめると、これにより、降順のステップを含む合計の生成が回避されます。
上記のアプローチは、プログラムが 1 回の実行後に終了することを前提としているため、メモリの解放について心配する必要はありません。その場合、おそらく作成したすべてのオブジェクトへのポインタを保存する必要があるため、それらをすべて解放できます。