私が認識しているこの種の問題の解決策には、偏った宝くじとフィルター処理/生成されたランダムシーケンスの 2つのカテゴリがあります。
最初に、状態を保持しない簡単で間違ったソリューションを省きましょう。状態を維持しない宝くじスタイルのソリューションでは、2項分布での勝利数があり、「何度も」の基準を満たしません。すべての人を等しく選択するランダムシーケンスを選択できます(リストを移動するだけで、順列はランダム性を提供します)。追跡しない限り、平等な労力を維持するのではなく、二項分布に再び気づくでしょう。
また、実際にランダムであることを約束します。これは、たとえば、決定論的アルゴリズムに基づいて休暇をスケジュールできないようにして、クロワッサンを購入する番になったときに(休暇をすべて使い切るまで)存在しないようにすることができます。 。
それでは、2つのタイプのソリューションについて説明します。
私たちはかなりから選ぶことができるという偏った宝くじ、最初のノート構築するためにすべての私たちの宝くじのための番号を生成する(有限偏差)連続分布を。敗者は、最小の番号を持つ人になることができます。次に、最も簡単なバイアスは、各個人が自分のシェアよりも多く買ったか少なく買ったかを追跡することです。クロワッサンの単位でバイアスを測定できます。分布の幅と形状を変更することにより、ランダム度を調整できます。これにより、個人が「同じ回数」からどれだけ離れることができるかが決まります。ガウシアンは簡単です。彼らは長すぎる(「不公平」)尾を持たずに合理的な驚きを可能にします。したがって、ソリューションの基本的な形は(Scalaコードで)
case class Employee(var bias: Double) {
def eat { bias -= 1 }
def buy(n: Int) { bias += n }
def roll = bias + stdev * Random.nextGaussian
}
あなたが最後に買った人を追跡し、彼らに多額のバイアスボーナス(例:)を与えて、10*stdev
休暇の構造が誰もが「最後の」時間を買ったことを許していたエッジの場合を除いて、人々が連続して2回購入するのを防ぐことができます。(つまり、購入してから休暇に行きます。)彼らが選択された日に存在しないのと同じことです。(誰かが存在しない場合は、一日おきに、彼らは最終的になり、彼らは彼らのバイアスボーナスを通じて燃やすとして出てくる。私は、この機能ではなく、バグを検討してください。)
そのため、その日の現在の従業員のリストを収集し、すべての人に宝くじに出向いてもらい、最低の人を選び、更新します。購入ボーナスを従業員数と同じにするかどうか(コストは無視できるが、クロワッサンを取得するための旅行は負担が大きい場合)、出席する従業員の数(旅行は簡単だがコストが負担になる場合は良い)を選択できます。 )、またはその間にあるもの(両方の負担を認識するため)。出席している人にのみ「食べる」ペナルティを課した方がいいでしょうが、休暇を取るだけでは適切な提案が得られないと感じた場合は、どちらの方法でも可能です。
フィルターされたランダムシーケンスを作成するには、最初にランダムシーケンスを生成する必要があります。従業員のリストをシャッフルすることは、開始するのと同じくらい良い方法です。毎日、リストを順番にたどってください。誰かがいないために購入できなかったり、以前に知らされたり購入したりできない場合は、スキップしてください。今、あなたは問題を抱えています:あなたはスキップされた人々を集めています。それでも大丈夫です。シーケンスの最後に達したら、シャッフルする前に、スキップした従業員のリストを完全なリストに追加します。これで、出現する確率はスキップされた回数に比例し、「同じ回数」のプロパティが維持されます。
log2(N)NN!NNlog2[(N!NN)1/N]≈−1log(2)+log22π/N√N≈−1.4NN=10 1.14
個人的には、ランダム性の制御が優れているため、バイアスのある宝くじの解決策を好みます。フィルター処理されたシーケンスを使用すると、シーケンスを生成するためのより複雑な方法を考え出すことができます。たとえば、ランダムな順列をとるのではなく、ローカルスワップを特定の距離まで実行するか、プールから完全にスワップアウトすることを許可します(ただし、スキップされたリストに移動します)。ただし、これらの処理には、より多くのアルゴリズムが必要です。宝くじでは、標準偏差を調整するだけです。