次の制約を満たすn個のランダムな実数値P[0]、P [1]、...、P[n-1]を生成する必要があります。
Pmin[0] <= P[0] <= Pmax[0]
Pmin[1] <= P[1] <= Pmax[1]
...
Pmin[n-1] <= P[n-1] <= Pmax[n-1]
P[0] + P[1] + ... + P[n-1] = S
これを効率的に行う方法はありますか?
次の制約を満たすn個のランダムな実数値P[0]、P [1]、...、P[n-1]を生成する必要があります。
Pmin[0] <= P[0] <= Pmax[0]
Pmin[1] <= P[1] <= Pmax[1]
...
Pmin[n-1] <= P[n-1] <= Pmax[n-1]
P[0] + P[1] + ... + P[n-1] = S
これを効率的に行う方法はありますか?
一般に、指定された範囲から一様にランダムに要素を選択する場合、この問題を解決することはできません。
例 1: Pmin[i] = 0、Pmax[i] = 1 とします。n = 10、S = 100 とします。この場合、可能な最大和は 10 であるため、解はありません。
例 2: Pmin[i] = 0 および Pmax[i] = 1 とします。n = 10 および S = 10 とします。この場合、厳密に 1 つの解があります。P[i] = 1 を選択します。
結果のシーケンスが可能な解のセットからランダムに一様に選択されるようなアルゴリズムを書くことができます。これは、P[i] が Pmin[i] と Pmax[i] の間で一様に分布しているということとはまったく異なります。
基本的な考え方は、次のように、各段階で範囲をさらに制限することです。
各 P[i] を選択するときにこれらのルールに従うことができれば、解決策があり、ランダムに 1 つ見つけることができます。そうでなければ、解決策はありません。
実際にこの選択ソリューションをランダムに作成するには、インデックスをシャッフルし、このアルゴリズムを実行してから、適切な順序になるようにシーケンスを再配置するのがおそらく最善であることに注意してください。O(n) でシャッフルし、このアルゴリズムを実行して (ソリューションをボトムアップで構築できるため、ここでは動的プログラミングをお勧めします)、結果のシーケンスを「アンシャッフル」してシーケンスを吐き出すことができます。
For every i, assign P[i] := Pmin[i]
Compute the sum
If sum>S, then stop (it's impossible)
For every i:
If P[i]+S-sum <= Pmax[i]
P[i] = P[i]+S-sum
Stop (it's done :-)
sum = sum+Pmax[i]-P[i]
P[i] = Pmax[i]
Go for next i
Stop (it's impossible)
おっと、すみません、あなたはランダムに言いました...それはそれほど些細なことではありません。私はそれについて考えてみましょう...
前のアルゴリズムを実行して、開始点を取得します。次に、上下の総マージンを計算します。上記のマージンは、すべての i の個々のマージン Pmax[i]-P[i] の合計です。以下のマージンは、すべての i の個々のマージン P[i]-Pmin[i] の合計です。
ランダムな順序で1 つを除くすべての要素をトラバースし、各要素を 1 回だけ訪れます。それらのすべてについて:
次に、合計 S に合わせて残りの要素を調整します。
ランダムな順序での走査については、Knuth shufflesを参照してください。