4

製品コンフィギュレータで可能な組み合わせの数を決定するためのルーチンをプログラムするように依頼されました。

設定は本当に簡単です。これよりも多くの機能がありますが、n個のオプションの1つを選択する必要があるいくつかの「ラジオグループ」(UIコントロールなど)としてモデル化できます。

使用できる制約の種類は、あるオプションが選択されている場合は別のオプションを選択できないというルールだけです。

したがって、私がやりたいのは、一連のオプショングループと制約を前提として、構成できるさまざまな製品の数を計算することです。

私は、包除原理を使用してこれを解決するための素朴なアプローチを行いました。ただし、私が見る限り、このメソッドに基づくアルゴリズムはすべてO(2 ^ n)で実行する必要があり、機能しません。もちろん、適切なランタイムを提供する可能性のある最適化はいくつかありますが、それでも簡単に構築できる最悪のシナリオがあります。

それは私が今いるところです。助言がありますか?

アップデート

ルールがどのように適用されるかを十分に説明していないことに気づきました。

オプション付きのグループがいくつかあります。各グループで選択する必要があるオプションは1つだけです。グループには1つ以上のオプションがあります。

制約のタイプは1つだけです。あるグループのオプションAが選択されている場合、他のグループのオプションBは選択できません。制約はいくつでもかまいません。オプショングループまたはオプション自体に適用される制約/ルールの数に制限はありません。

したがって、例は次のようになります。

グループ1:
x1 x2 x3 x4 x5

グループ2:
y1 y2 y3

グループ3:
z1 z2 z3 z4

制約:
x1 <-> y2 *
x1 <-> z4
y2 <-> z2

*group1でオプションx1が選択されている場合、グループ2のオプションy2は選択できません。

包含-除外を使用して、組み合わせの数を次のように計算します

組み合わせ=Cルールなし--Cr -- C r [2] --C r [3] + C r [1,2] + C r [1,3] + C r [2,3] --C r [1、 2,3][1]

どこ

Cルールなし=5* 3 * 4

C r [a、b、c] =ルールa、b、およびcに違反する組み合わせの数。

残念ながら、この方法には2^|ルール|が必要です。計算。

4

11 に答える 11

3

わかりました。2^Nを取得することはできませんが、サンプルセットを減らすことはできます。これを行うために、「構成された制約」を計算します。構成された制約は、左側のすべてのオプションが選択されている場合、右側のオプションを選択できない制約ですが、左側のオプションに基づく他の制約は適用されません。

一連の制約から、すべての可能な合成制約のセットを計算する必要があります。必須ではありませんが、右手のグループが左のグループよりも小さい場合は、左手と右手を入れ替えて既存の制約を「修正」します。これにより、いくつかの構成された制約が軽減される可能性がありますが、スワッピングにはより優れたヒューリスティックが可能です。

また、グループごとに任意に選択できるオプションの「最小セット」を計算する必要があります。この最小セットは、使用可能なオプションのリストから、構成された制約の左側に表示されるオプションを削除することによって計算されます。

アルゴリズムが続きますが、CCが正しく計算されることを証明していません。もしそうなら、それらを使用して可能な組み合わせの数を計算できることを証明します。

  1. 左手のグループが右手のグループ以下になるように制約を修正します。
  2. 制約を作成します。

    1. 制約を左手で並べ替える
    2. 続いて、制約ごとに:

      1. 同じ左手でそれに続くすべての制約で制約を折り、、を回しx1 <-> y1x1 <-> y2...x1 <-> yNSet(x1) <-> Set(y1 ... yN)
      2. 次の場合は、すでに折りたたまれている各制約を使用して、折りたたまれた制約を作成します。
        • x1は、すでに折りたたまれている制約の右側にはありません
        • x1は、左側のどの要素の同じグループにも含まれていません
      3. 折りたたまれた制約とそのすべての構成を折りたたまれた制約のセットに追加します
  3. すべてのオプションを選択し、固定制約の左側に表示されているオプションを削除して、最小セットを計算します。

これで、次の式を使用して組み合わせの数を計算できます。CCを合成制約と呼びましょう。その場合、組み合わせの数は次のとおりです。

C(Mininum Set) + CCC1 + ... + CCCn

どこ:

  • C(最小セット)は、最小セットで可能な組み合わせの数です。
  • CCCxは、最小セットを取得し、CCxの左側にオプションがあるグループをそのオプションに置き換えてから、CCxの右側にあるオプションを削除することで可能な組み合わせの数です。

式は純粋に加算的であることに注意してください。つまり、その式で期待される結果が得られるには、次の2つの条件が満たされている必要があります。

  1. その2つの用語に同じ組み合わせを含めることはできません。
  2. すべての組み合わせは、これらの用語で説明する必要があります。
  3. どの用語でも無効な組み合わせを生成することはできません。

最初の証明として、同じ左手に2つの異なるCCがないことに注意してください。2つのCCの左手が同じで右手が異なる場合、一方のCCに適用する必要のある追加の制約があるか、もう一方のCCに無効な制約が適用されていることを意味します。

同じ左手を持つ2つのCCはなく、最小セットには定義上どのCCの左手も含まれていないため、2つのCCは、一方に対して選択され、他方に対しては選択されない少なくとも1つのオプションによって区別できます。 。したがって、2つのCCが同じ組み合わせを生成することはできません。

2番目の証明として、CCのセットには、定義上、左側のオプションのすべての有効な組み合わせが含まれていることに注意してください。

最小セットにもCCのセットにも表示されない組み合わせが1つあると想定します。この組み合わせに左側のオプションが含まれていない場合は、定義上、最小セットの組み合わせである必要があります。したがって、左手からのオプションが含まれている必要があります。

CCのセットには左側の有効な組み合わせがすべて含まれているため、同じ左側のオプションを持つCCが1つあります。したがって、この組み合わせには、そのCCのどの組み合わせにも含まれないオプションが必要です。ただし、そのCCに含まれていないオプションは、他のCCの左側に表示されるオプションと、制約によって除外する必要があるオプションのみです。どちらも当てはまらない可能性があるため、この組み合わせは存在できません。

3番目の証明として、最初に最小セットについて考えてみましょう。最小セットには、グループの左側にオプションが含まれていません。すべての制約は1つの左側と1つの右側のオプションの間にあるため、最小セットには制約は適用されません。

それでは、CCについて考えてみましょう。CCには、定義上、左側のオプションの有効な組み合わせがあります。その左手と互換性のないオプションはすべて右手に表示する必要があり、その右手からのオプションは最小セットから削除する必要があります。そもそもそれらの間で互換性がない最小セットにはオプションがないため、CCのどの組み合わせでも満たされない制約はあり得ません。

そして、それで証明は終わりです。

コメントの例を使用して、これがどのように適用されるかを見てみましょう。

G1: x1, x2, x3 
G2: y1, y2 
G3: z1, z2, z3 

R1: x1 <-> y2 
R2: x3 <-> y2 
R3: y1 <-> z1 
R4: y2 <-> z2 
R5: y2 <-> z3

CC1: {x1} <-> {y2}
CC2: {x3} <-> {y2}
CC3: {y1} <-> {z1}
CC4: {x1, y1} <-> {y2, z1}
CC5: {x3, y1} <-> {y2, z1}
CC6: {y2} <-> {z2, z3}

リストにない構成されたグループについて簡単に考えてみましょう。

R1&R2: {x1, x3} <-> {y2} -- not in the list because x1 and x3 belongs to the same
                            group
R1&R5: {x1, y2} <-> {y2} -- not in the list because the left hand of R2, y2
                            appears in the right hand of R1

次に、各セットで可能なオプションを見てみましょう。

Minimum Set: (x2), (), (z1, z2, z3)    
CC1: (x1), (), (z1, z2, z3) -- replace G1 with x1, remove y2 from G2
CC2: (x3), (), (z1, z2, z3) -- replace G1 with x3, remove y2 from G2
CC3: (x2), (y1), (z2, z3)   -- replace G2 with y1, remove z1 from G3
CC4: (x1), (y1), (z2, z3)   -- replace G1 with x1, G2 with y1, remove y2 and z1
CC5: (x3), (y1), (z2, z3)   -- replace G1 with x3, G2 with y1, remove y2 and z1
CC6: (x2), (y2), (z1)       -- replace G2 with y2, remove z2 and z3 from G3

さて、物事を追加しましょう:

C(Minimum Set) = 1 * 0 *3 = 0
CCC1 = 1 * 0 * 3 = 0
CCC2 = 1 * 0 * 3 = 0
CCC3 = 1 * 1 * 2 = 2
CCC4 = 1 * 1 * 2 = 2
CCC5 = 1 * 1 * 2 = 2
CCC6 = 1 * 1 * 1 = 1

C(Minimum Set) + CCC1 + CCC2  + CCC3 + CCC4 + CCC5 + CCC6
0              + 0    + 0     + 2    + 2    + 2    + 1    = 7

ここにもう1つ考えを追加します。5つのルールに対してCCCは6つしかなく、他の方法で予想される32の用語よりもはるかに少ないですが、ルールごとに、これまでに作成されたすべてのCCCと比較して組み合わせる必要があるため、これらのCCCは2^Nの最悪の時間で計算されます。それらは2進数と考えることができます。ここで、ルールが結合されている場合はビットが設定され、そうでない場合は設定されません。

ただし、互換性のない組み合わせはすぐに破棄されるため、新しいルールを組み合わせるたびに、すでに無効と見なされている組み合わせで時間が失われることはありません。また、ルールを事前に並べ替えることで、同じグループ内の連続するルールを、適切なデータ構造で非互換性をテストすることなく破棄できます。

この特定の例が示すように、平均時間は2^Nよりもはるかに優れている可能性があります。

代替アルゴリズムと考慮事項

2-SATと3-SATの話があります。私には、これは2-SATの問題であるように思われます。つまり、すべての制約a <-> bは、実際には句 "!a ||!b"であるという意味です。したがって、すべての制約をまとめて、「(!x1 ||!y2)&&(!x1 ||!z4)&&(!y2 &&!z3)」などと書くことができます。つまり、ある意味で「解決」できるということです。これを真にする各オプションへのブール割り当てがあるかどうかを確認できます。Aspall、Plass、Tarjanによるこのための線形アルゴリズムがあり、ここにスライドプレゼンテーションがあります。

しかし、制約を解決できるかどうかを知ることは、求められたものではありません。質問されたのは、2-SATの問題を真に保ちながら、すべてのオプションを設定できる方法の数です。

現在、2-SAT問題を満たす方法の数を数えるための効率的なアルゴリズムがあります。たとえば、このペーパーは、1.2561nで実行されるアルゴリズムを紹介します。しかし、それでも、そのソリューションを満たす組み合わせの数を計算できるようにするためのソリューションを知る必要があるため、役に立ちません。

ウィキペディアによると、この論文には、すべてのソリューションを効率的に列挙するアルゴリズムがあります。これは私たちが望んでいることです。しかし、カウントがすでに指数関数的である場合は、列挙されます。おそらく2nよりも優れていますが、それでも指数関数的です。

2-SAT問題のすべての解決策を列挙すると、各グループの組み合わせの数は、オプションが選択されていない各グループの無料オプション(制約に表示されないオプション)の数を掛けた1で与えられます。解決策によって。

たとえば、前のグループと制約のセットを取り上げます。相互排除を含む2-SATの問題は次のとおりです。

(!x1 ||!y2)&&(!x3 ||!y2)&&(!y1 ||!z1)&&(!y2 ||!z2)&&(!y2 ||!z3)&&(!x1 || !x3)&&(!y1 ||!y2)&&(!z1 ||!z2)&&(!z1 ||!z3)&&(!z2 ||!z3)

最初の行は5つのルールです。2行目は、制約ルールに表示される同じグループ内のすべてのオプションの相互排除です。

この2-SAT問題の解決策は次のとおりです。

x1    x3    y1    y2    z1    z2    z3    Combinations
true  false true  false false true  false 1
true  false true  false false false true  1
true  false true  false false false false 0
true  false false false true  false false 0
true  false false false false true  false 0
true  false false false false false true  0
true  false false false false false false 0
false true  true  false false true  false 1
false true  true  false false false true  1
false true  true  false false false false 0
false true  false false true  false false 0
false true  false false false true  false 0
false true  false false false false true  0
false true  false false false false false 0
false false true  false false true  false 1
false false true  false false false true  1
false false true  false false false false 0
false false false true  true  false false 1
false false false true  false false false 0
false false false false true  false false 0
false false false false false true  false 0
false false false false false false true  0
false false false false false false false 0

最初の2つのソリューションでは、オプションが選択されていないグループがないため、組み合わせの数は1です。3番目のソリューションでは、グループG3に対してオプションが選択されていないため、1に0を掛けます。 false」、グループG1に選択されたオプションはなく、1つの無料オプション:x2。したがって、1を1で乗算し、G2またはG3でオプションが選択されていない場合は0を乗算します(この場合、空きオプションの数は0です)。

ここで、各グループで選択されている1つのオプションを強制し、それでも2-SATであると主張するにはどうすればよいかという問題があります。前述のように、問題には2つの暗黙の制約があります。グループごとに1つだけのオプションを選択する必要があります。これらの2つの制約は、次のように記述できます。

    x 1 || x 2 || x 3(オプションx1のグループxの場合..x 3 (     !x 1 ||!x 2)&&(!x 1 ||!x 3)&&(!x 2 ||!x 3

後者の制約は2-SATであり、前者は重要なケースでは3-SATです。たまたま、最初の制約を適用しませんが、カウントは0になります。カウントアルゴリズムは次のようになります。

  • 制約のない組み合わせの場合は、各グループの制約のないオプションの数を互いに乗算します。
  • 制約と完全な組み合わせの場合、次のカウントの結果を追加します。
    • ソリューションごとに、互いに「真」と評価されたオプションを使用せずに、各グループの制約のないオプションの数を掛けます。

したがって、制約のないオプションが少なくとも1つあるすべてのグループについて、選択は暗黙的で匿名です。すべてのオプションが何らかの制約の一部であるすべてのグループについて、オプションが選択されていない場合、そのグループのカウントは0になるため、そのソリューションの組み合わせの数も0になります。

これは、有効な>2-SAT制約から問題をだましているように感じます。結局のところ、これが可能であれば、3-SATの問題は、その2-SAT部分の解を列挙し、3-SAT部分を満たさないものをすべて破棄するだけで解決できます。残念ながら、私が特定できる根本的な違いが1つあります。

  • 問題の2-SAT部分で解決されないすべての述語には、それ以上の制約はありません。

句に対するこのかなり制限的な制約を考えると、2-SATの明示的な制約の解を列挙することでこの問題を解決できます。

誰かがこれをさらに追求したいなら、先に進んでください。私が提案した2nソリューションの改善に満足しています。

于 2009-07-25T14:33:44.630 に答える
2

Nオプショングループがある場合は、それぞれにXiオプション(0<=i<N)があります。

X0*X1*...*X(N-1)

あなたが望む答えを与えます。つまり、オプションの各グループのサイズを乗算します。

于 2009-07-20T16:39:55.373 に答える
1

一般的な場合のショートカットはここにはありません。 思ったほど悪くはありません。以下の「再考」を参照してください。

2 ^ nは本当に悪いですか?ここで話している除外ルールはいくつですか?ルール/オプションのセットが絶えずオンザフライで変更され、動的な再計算が必要な場合を除いて、実際には、コンフィギュレーターごとに1回だけこれを行う必要があります。本当に膨大な数のルールがある場合、正確な解決策を探すことはしません。k次の交差を考慮し、「組み合わせの数は少なくとも/ほとんどです...」と言うだけです。答えの限界をすばやく導き出すことができる他のふるい法があるかもしれません。

また、実際に必要な除外のみを考慮する場合、2 ^ nは単なる上限であり、実際のシナリオでは実際の計算数が大幅に少なくなる可能性があることにも注意してください。つまり、C [1,2]がゼロの場合、C [1,2、...]もゼロになります。これを考慮してください。制約ごとに、共通のオプションを共有している場合は、制約のセットを「まとめて」まとめます。実際の実行時間は、最大の「クランプ」のサイズによって定義されることは明らかです(もちろん、nと同じくらい大きい場合があります)。


再考:ほとんどの場合、C [x、y]はゼロになります。制約は、別のグループが関与する他の制約とのみオーバーラップできます。つまり、(x1 <-> y1)は、(x1 <-> z1)または(y1 <-> z2)などとのみオーバーラップでき、(x1 <-> y2)とはオーバーラップできません。同様に、一連の制約は新しいグループとのみオーバーラップできます。(x1 <-> y1)と(y1 <-> z2)の組み合わせには、(x3 <-> z2)との相互作用はありません(xグループはすでに修正されています) x1で)。組み合わせに追加する各ルールが、以前は変更されていないグループをミックスに追加する場合にのみ、包含/除外を考慮する必要があります。つまり、実際にはO(2 G)です。ここで、Gはグループの数です(また、グループのサイズに基づいて異なる境界もあります)。はるかに管理しやすい!

于 2009-07-24T16:10:14.907 に答える
1

各パラメーターと制約に可能な値を持つnパラメーターがある場合、構成数の上限は次のようになります (制約は無視されます)。Cim

N0 = C1 * C2 * ... * Cn

フォームの 1 つの制約によりci == x => cj != y、次の数の構成が許可されません。

        N
Dk = -------
     Ci * Cj

したがって、構成の数は、制約を無視して上限から許可されていない構成を差し引くことによって得られます。

N = prod(Ci, i = 1...n) * (1 - sum(1 / (Cxj * Cyj), j = 1...m))

ここでxjとは、 -th 制約yjからの両方のパラメーター インデックスです。j

Parameters    n = 4

Parameter 1   C1 = 4   0 1 2 3 
Parameter 2   C2 = 3   4 5 6 
Parameter 3   C3 = 2   X Y
Parameter 4   C4 = 3   7 8 9

Constraints   m = 2

Constraint 1  c2 == 4 => c3 != X
Constraint 2  c3 == X => c4 != 9

N0 = 4 * 3 * 2 * 3 = 72

D1 = 72 / (3 * 2) = 12
D2 = 72 / (2 * 3) = 12

N = 72 - (12 + 12) = 48

アップデート

制約の依存関係を考慮していないため、これはまだ完全には正しくないと思います。

于 2009-07-20T17:18:12.083 に答える
1

これは直接役立つ答えではないかもしれないので、無視してかまいません...ただし; 私は現在、同様のシステムを自分で使用していません。率直に言って、些細な例を除いて、有効な組み合わせの数を計算しようとすることが有用かどうかはわかりません。例として、私が現在取り組んでいるモデルには、(たとえば) 18000 の候補アイテムが 80 以上の選択にまたがり、いくつかは単一選択/いくつかは複数選択されています。最小のモデルを超えて、完全な真理値表としてそれを書くことは絶対にないので、数を知っていても何のメリットもありません。あなたはかなり強制されていますルールをオンデマンドで実行する (つまり、有効でなくなったものをすべて削除し、必要に応じて自動選択し、違反しているルールがないことを確認します)。これは必ずしも問題ではありません。私の現在のコードは、このモデルを (Web サービスとして) 約 450 ミリ秒で処理します。そのほとんどは、実際には入出力用の xml の処理に費やされた時間です。入力/出力が xml でない場合、約 150 ミリ秒になると思います。これはすばらしいことです。

雇用主にエンジンをオープンソースにするよう説得したいです。ただし、それは別の日の戦いです。

于 2009-07-26T08:01:21.523 に答える
1

編集

このアルゴリズムは正しくありません。別の投稿で別の回答を提示しましたが、これは最悪の場合でも 2^N ですが、それ以外の場合はより良い結果が得られる可能性があります。

これは、y2 が x1 の除外セットの一部であり、最初の 2 つの制約が x1 に基づいているため、選択した例で機能します。それでも、今何をすべきかが見えてきました。まだ 2^N に近いですが、大幅な向上につながる最適化があります。

このアルゴリズムを修正するには、構成されたルールを set(ox) <-> set(oy) の形式にする必要があります。それらを構成するには、構成する左側の oX を持つ各制約に対して、oX が構成されたルールの右側の一部でなく、そのグループがグループの左側と同じです。

完全に独立した制約の場合、これは 2^N です。それ以外の場合は、次のようにして N を減らします。

  • 制約を共通の左手で統一する
  • 相互に排他的なルールの組み合わせを計算しない場合、これは次のように分割されます。
    • 同じグループ内のオプションのルールを組み合わせない
    • 一方の左側が他方の右側に現れるルールを組み合わせない

このアルゴリズムを修正する価値はないと思います。それはかなりメモリが重く、私の別の答えとまったく同じ順序になり、はるかに軽量になります。

編集を終了

これをひっくり返しましょう。アルゴリズムの場合はどうですか:

  1. 必要に応じてルールを修正し、 ruleo1 <-> o2に対して、group(o1) < group(o2)
  2. oX <-> o?すべてのルールを 1 つのルールにまとめることで、 「構成された」ルールを計算します。oX <-> Set(o?)
  3. グループからすべてのルールの左側のオプションを削除することにより、グループの「クリーンな」セットを計算します
  4. 左側のオプションのグループを左側のオプション自体で置き換え、他のグループからルールの右側のオプションを差し引くことにより、構成されたルールごとに 1 つずつ、クリーン セットから代替セットを計算します。
  5. グループのセットごとに、セット内の各グループのオプションの数を掛けて、組み合わせの数を計算します。
  6. ステップ 5 のすべての結果を追加します。

これを実際に見てみましょう:

Group 1:
x1 x2 x3 x4 x5

Group 2:
y1 y2 y3

Group 3:
z1 z2 z3 z4

Constraints (already fixed):
x1 <-> y2 *
x1 <-> z4
y2 <-> z2

Composed rules:
x1 <-> (y2, z4)
y2 <-> (z2)

Clean set of groups:
x2x3x4x5, y1y3, z1z2z3z4

Alternate sets:
x1, y1y3, z1z2z3 (first composed rule)
x2x3x4x5, y2, z1z3z4 (second composed rule)

Totals:
4 * 2 * 4 = 32
1 * 2 * 3 = 6
4 * 1 * 3 = 12

Total: 50

さて、おそらくこのアルゴリズムは正しくありません。今のところ、私はそれが正しいかどうかを証明するのに十分明確に考えることができません.私はあまりにも長い間問題に近づきすぎていました. しかし、例と照合してみましょう:

c(no rules) = 60
c1 => 4
c2 => 3
c3 => 5
c12 => 1
c13 => 1
c23 => 0
c123 => 0

c(no rules) - c1 - c2 - c3 + c12 + c13 + c23 - c123 = 50

私のアルゴリズムが正しければ、それは多項式のようです。繰り返しますが、今は十分に明確に考えることができず、セットでの操作の大きな問題を考慮する必要があります。

以下はその Scala 実装です。

case class GroupOption(id: Int, option: Int)
case class Group(id: Int, options: Set[Int])
case class Rule(op1: GroupOption, op2: GroupOption)
case class ComposedRule(op: GroupOption, set: Set[GroupOption])

object ComputeCombinations {
  def fixRules(rules: Set[Rule]) = {
    rules map (rule => if (rule.op1.id > rule.op2.id) Rule(rule.op2, rule.op1) else rule)
  }

  def ruledOptions(id: Int, rules: Set[Rule]): Set[Int] = (
    rules 
    filter (rule => rule.op1.id == id)
    map (rule => rule.op1.option)
  )

  def cleanseSet(groups: Set[Group], rules: Set[Rule]) = {
    groups map (group => 
      Group(group.id, group.options -- ruledOptions(group.id, rules)))
  }

  def composeRules(rules: Set[Rule]): Set[ComposedRule] = Set(
    (
      rules.toList
      sort (_.op1.id < _.op1.id)
      foldLeft (List[ComposedRule]())
      ) { (list, rule) => list match {
        case ComposedRule(option, set) :: tail if option == rule.op1 =>
          ComposedRule(option, set + rule.op2) :: tail
        case _ => ComposedRule(rule.op1, Set(rule.op2)) :: list
      }} : _*
  )

  def subset(groups: Set[Group], composedRule: ComposedRule) = (
    groups
    filter (_.id != composedRule.op.id)
    map (group => Group(group.id, group.options -- 
                                  (composedRule.set 
                                   filter (_.id == group.id)
                                   map (_.option)
                                  )))
  )

  def subsets(groups: Set[Group], composedRules: Set[ComposedRule]) = (
    composedRules map (composedRule => subset(groups, composedRule))
  )

  def combinations(groups: Set[Group]) = (
    groups.toList map (_.options.size) reduceLeft (_*_)
  )

  def allCombinations(groups: Set[Group], rules: Set[Rule]) = {
    val fixedRules = fixRules(rules)
    val composedRules = composeRules(fixedRules)
    val cleanSet = cleanseSet(groups, fixedRules)
    val otherSets = subsets(cleanSet, composedRules)
    val allSets = otherSets + cleanSet
    val totalCombinations = allSets.toList map (set => combinations(set)) reduceLeft (_+_)
    totalCombinations
  }
}

object TestCombinations {
  val groups = Set(Group(1, Set(1, 2, 3, 4, 5)),
                   Group(2, Set(1, 2, 3)),
                   Group(3, Set(1, 2, 3, 4)))
  val rules = Set(Rule(GroupOption(1, 1), GroupOption(2, 2)),
                  Rule(GroupOption(1, 1), GroupOption(3, 4)),
                  Rule(GroupOption(2, 2), GroupOption(3, 2)))
  def test = ComputeCombinations.allCombinations(groups, rules)
}
于 2009-07-25T03:03:30.443 に答える
0

これは、上記のsdcvvcの優れた回答で簡単に説明されていますが、モンテカルロ近似で十分でしょうか?N個のランダム構成を生成し(Nは、実験の能力が十分に高くなるように選択されます。ここで役立つかどうかはわかりません)、制約と互換性のある構成がいくつあるかをテストします。その比率を残りの構成スペースに外挿します。

于 2009-07-28T08:47:00.677 に答える
0

あなたの問題はかなり実行不可能です。

  • ラジオボックスのすべてのグループを 2 つのオプションに制限したとしても、解の数を数えることは #P-complete です
  • 制約と一致するオプションの選択肢があるかどうかを確認することは NP 完全です
  • ラジオボックスのすべてのグループを 2 つのオプション (2SAT) に制限すると、制約と一致するオプションの選択肢があるかどうかを非常に高速に確認できます。

したがって、一般に、多項式アルゴリズムを当てにしないでください。そのようなアルゴリズムの存在は、P=NP を意味します。

できること:

  • 近似アルゴリズムを使用します。私がリンクしたウィキペディアの記事によると、彼らはしばしば彼らに疑わしい.
  • SATソルバーhttp://en.wikipedia.org/wiki/SAT_solverまたは関連するカウント用ツールを使用します(残念ながら私は何も知りません)。人々は多くのヒューリスティックを作成しており、そのプログラムは一般に自家製のソリューションよりもはるかに高速です。SAT の大会もあるので、この分野は現在非常に急速に拡大しています。
  • そのような一般性が必要かどうかを確認してください。おそらく、問題には追加の仮定があり、これにより複雑さが変わります。

証明:

  1. 解の数を数えることは #P であることが簡単に示されるので、2SAT をこれに減らすだけで十分です。次のように、2SATインスタンスをいくつか取ります

(p1 or not p2) and (p2 or not p3)

ユーザーが p1、p2、p3 の値を選択できるようにします。これを解決可能にする制約を簡単に形成できます。したがって、可能な構成の数 = ブール式を真にする p1、p2、p3 の可能な割り当ての数です。

  1. オプションの選択が許可されているかどうかは簡単に確認できます。これはNPなので、3SATをこれに減らすだけで十分です。次のように、3SATインスタンスをいくつか取ります

(p1 or p2 or not p3) and (p2 or not p1 or p4)

オプションを与える:

グループ p1 p1true p1false

グループ p2 p2false p2true

グループ p3 p3false p3true

グループ p4 p4false p4true

group clause_1 c1a c1b c1c

group clause_2 c2a c2b c2c

clause_1 は最初の節 (p1 または p2 または p3 以外) を制御します。正確には、p1true が選択された場合は c1a がチェック可能になり、p2true が選択された場合は c1b がチェック可能になり、p3false が選択された場合は c1c がチェック可能になります。したがって、制約は次のとおりです。

p1false <-> c1a

p2false <-> c1b

p3true <-> c1c

句_2と同じ、制約は

p2false <-> c2a

p1true <-> c2b

p4false <-> c2c

ユーザーがすべての回答を選択できる場合 (構成の数が > 0 の場合)、3SAT インスタンスを真にする変数 p1、...、p4 の評価があることを証明します。逆に、ユーザーが仮定と一致する回答を選択できない場合 (利用可能な構成の数 = 0)、3SAT インスタンスは満足できません。したがって、答えが > 0 であるかどうかを知ることは、3SAT インスタンスが解けるかどうかを知ることを意味します。

もちろん、この削減は多項式時間です。証明終わり。

答えが 0 になる可能性があるという事実に満足できない場合: そのようなコンフィギュレーターを無視しても、依然として NP 困難です。(すべてのグループにいくつかの「偽の」オプションを追加し、「偽の」が選択されていない場合は指数関数的に多くの選択肢を許可します。これは説明が複雑なので、要求に応じて行います。)

于 2009-07-26T21:23:11.817 に答える
0

ザックは正しい方向に考えていると思います。組み合わせ数の式を見ると、2 次項 Cr[i,j] が C[k] 項よりもはるかに小さいことがわかります。各軸がオプションのグループである立方体を想像してください。立方体の各ポイントは、オプションの特定の組み合わせを表します。一次 C[k] 補正は、立方体の 2 つの面の間の一連のオプションを除外します。二次補正 C[i,j] は、そのような 2 本の線が立方体の空間で 1 点 (オプションの組み合わせ) で交わる場合にのみ発生します。したがって、グループの数に関係なく、高次の修正は常にますます小さくなります。あなたが固執するなら

組み合わせ = C(ルールなし) - Cr[1] - Cr[2] - Cr[3]

組み合わせの数の下限になります。一次補正のサイズがわかったので、上記の立方体での観察について考えれば、二次補正の大きさの桁を見積もることもできます。団体数によって異なります。その後、アルゴリズムは、より高い注文を続行するか、停止するかを決定できます。

于 2009-07-24T18:39:44.217 に答える
0

n はオプションの数、x はオプションごとの選択肢の数です。

于 2009-07-20T16:37:25.550 に答える