靴下引き出しをシミュレートする


16

バックグラウンド

「平日靴下」のコレクションがあります。これは、曜日によってラベル付けされた7足の靴下です。私が靴下を洗うと、それらは山になってしまいます。クローゼットに入れる前に正しいペアに揃えなければなりません。私の戦略は、一度に山からランダムな靴下を1つずつ引き出し、引き出しに置くことです。引き出しに一致する靴下のペアがある場合は、つなぎ合わせてクローゼットに入れます。あなたの仕事は、このランダムなプロセスをシミュレートし、最初に一致するペアを見つけるのに必要なドローの数を返すことです。

入力

入力は整数N≥1です。これは「1週間の日数」を表します。パイルにはNペアの靴下があり、各ペアには個別のラベルがあります。必要に応じて、入力としてPRNGシードを使用することもできます。

出力

出力は、最初に一致するペアが見つかるまでに描画する必要がある靴下の数です。たとえば、最初の2つの靴下がすでに一致するペアを形成している場合、出力は2です。

もちろん、出力はランダムであり、描画順序に依存します。描画順序はすべて同じであると想定しているため、靴下を描画するたびに選択肢は均一であり、他のすべての選択肢から独立しています。

レッツN = 3私たちは、合計、ラベルに6つの靴下を持っているので、こと、AABBCC。「sock-drawing protocol」の実行の1つは次のとおりです。

       | Pile   | Drawer | Pairs
Begin  | AABBCC | -      | -
Draw B | AABCC  | B      | -
Draw C | AABC   | BC     | -
Draw B | AAC    | C      | BB
Draw A | AC     | AC     | BB
Draw A | C      | C      | AA BB
Draw C | -      | -      | AA BB CC

最初に一致するペアは、2番目のBを描画した後に検出されました。これは、描画される3番目の靴下でしたので、正しい出力は3です。

ルールとスコアリング

完全なプログラムまたは関数を作成できます。最小のバイトカウントが優先され、標準の抜け穴は許可されません。入力と出力は、単項(1sの文字列)を含む任意の妥当な形式にすることができます。

あなたの言語のビルトインRNGは完璧だと思うかもしれません。出力に正しい確率分布がある限り、実際に靴下描画プロトコルをシミュレートする必要はありません。

「テストケース」

入力N = 7の場合のすべての出力のおおよその確率は次のとおりです。

Output       2     3     4     5     6     7     8
Probability  0.077 0.154 0.210 0.224 0.186 0.112 0.037

ソリューションをテストするには、たとえば40 000回実行して、出力分布がこれにかなり近いかどうかを確認します。


25
Draw all socks. End up with an odd number.
実生活


それで、n = 8は1-> 7に等しくなく、そして再び1に等しくありませんか?すなわち、1というラベルの付いた4つの靴下
Viktor Mellgren

@ViktorMellgrenいいえ、8つの異なるラベルがあります。
ズガルブ

私は同じ靴下でいっぱいの引き出しを持っているので、それらを整理する必要はありません。
JDługosz

回答:


9

ゼリー、8 バイト

ḤX€Ṛ<RTḢ

オンラインでお試しください!またはN = 7の分布を確認します。

バックグラウンド

してみましょうn個のペアの数です。ある2n個の個々の靴下は。

最初のドローでは、2n個の靴下があり、そのうちの0 が一致するペアになります。したがって、成功の確率は0 / 2n = 0です。

最初の引き分けが成功しなかったため、パイルには2n-1個の靴下があり、そのうち1個が一致するペアになります。したがって、成功の確率は1 /(2n-1)です。

2番目のドローが成功しなかった場合、パイルには2n-2個の靴下があり、そのうち2個が一致するペアになります。したがって、成功の確率は2 /(2n-2)です。

一般に、最初のk個のドローが失敗した場合、2n-k個の靴下が山にあり、そのうち2個が一致するペアになります。したがって、成功の確率はk /(2n-k)です。

最後に、最初のn個のドローがどれも成功しなかった場合、パイル上に2n-k個の靴下があり、それらすべてが一致するペアになります。したがって、成功の確率はn /(2n-n)= 1です。

使い方

ḤX€Ṛ<RTḢ  Main link. Argument: n

Ḥ         Unhalve; yield 2n.
 X€       Map `random draw' over [1, ..., 2n], pseudo-randomly choosing an integer
          from [1, ..., k] for each k in [1, ..., 2n].
   Ṛ      Reverse the resulting array.
     R    Range; yield [1, ..., n].
    <     Perform vectorized comparison.
          Comparing k with the integer chosen from [1, ..., 2n - (k - 1)] yields 1
          with probability (k - 1) / (2n - (k - 1)), as desired.
          The latter half of elements of the left argument do not have a counter-
          part in the right argument, so they are left untouched and thus truthy.
      T   Truth; yield all indices of non-zero integers.
       Ḣ  Head; extract the first one.

8

ゼリー、8バイト

Rx2ẊĠṪ€Ṃ

オンラインでお試しください!

R    generate [1, 2, ..., n]
x2   duplicate every element (two socks of each pair)
Ẋ    shuffle the list, to represent the order in which socks are drawn
Ġ    group indices by value. this will produce a list of pairs of indices;
       each pair represents the point in time at which each of the corresponding
       socks were drawn
Ṫ€   take the last element of each pair. this returns an array of n integers
       which represent the points in time at which a matching sock was drawn
Ṃ    minimum, find the first point at which a matching sock was drawn

確認のために、目的の出力と「シャッフルリスト」操作の結果の両方を表示するバージョンを次に示します(ソックスが描画された順序を確認するため)。


5

Python、66バイト

from random import*
f=lambda n,k=1:k>randint(1,n*2)or-~f(n-.5,k+1)

デニスは、物事を整理し、5バイトを節約する賢い方法を考えました。


4

MATL16 15バイト

Q:"r@qGEy-/<?@.

オンラインでお試しください!または、N = 7の場合の1000サンプルの経験的分布観察します(しばらく時間がかかります)。

これにより、確率分布に基づいて、結果を表すランダム変数が直接生成されます。してみましょうNは、靴下のペアの数である、と聞かせたpkは確率を表す)のk番目のドローが事実上の条件、成功するとkは -1番目のドローが成功しませんでした。次に(こちらも参照):

  • p(1)は明らかに0です。1つの靴下とペアにすることはできません。
  • p(2)は1 /(2 * N -1)です。2回目の抽選では、残りの2 * N -1の靴下から選択できる1つの優勝靴下があります。
  • p(3)は2 /(2 * N −2)です。3回目の抽選では、2 * N −2のうち2つの勝利の靴下があります。2回目の引き分けの後に手に入れた2つの靴下が異なっていたため、優勝した靴下の数は2です。
  • 一般に、同じ推論により、pk)は(k -1)/(2 * Nk +1)
  • 上記の式により、pN +1)は1です。N +1番目のドローに到達すると、成功することが保証されます。

そのため、コードは最大N +1の描画を繰り返します。でKランダム変数は確率(と1に等しいが生成される描画番目のK -1)/(2 * N - K、またはそれ以外は0)。ランダム変数が1に等しい(描画が成功した)たびに、プロセスは停止し、現在のkが出力されます。

Q:      % Input N implicitly. Generate [1 2 ... N+1] (values of draw index, k)
"       % For each
  r     %   Random variable uniformly distributed on the interval (0,1)
  @q    %   Push iteration index, k-1
  GE    %   Push 2*N
  y     %   Duplicate: push k-1 again
  -     %   Subtract: gives 2*N-k+1
  /     %   Divide: gives (k-1)/(2*N-k+1)
  <     %   Push 1 if random value is less than (k-1)/(2*N-k+1), 0 otherwise
  ?     %   If we got a 1
    @   %     Push k
    .   %     Break loop
        %   End if implicitly
        % End loop implicitly
        % Display implicitly

1
あなたと私は同じ考えを持っていましたが、あなたはMATLを知っています:)
プログラムマン

3

MATL14 13バイト

EZ@G\&=XRafX<

オンラインでお試しください!または、N = 7の場合の4000サンプルの経験的分布観察します(しばらく時間がかかります)。

E      % Input N implicitly. Multiply by 2
Z@     % Random permutation of [1 2 ... 2*N]
G\     % Modulo N: random permutation of [0 0 1 1 ... N-1 N-1]
&=     % Compare all pairs for equality. Gives an N×N matrix
XR     % Upper triangular part excluding the diagonal
a      % True for each column if it contains at least one true entry
f      % Get indices of true values
X<     % Take minimum. Implicitly display

3

JavaScript、77 73バイト

n=>{p={};for(i=n;i--;p[i]=2);while(--p[n*Math.random()|0])i++;return i+2}

説明

var f = (n) => {
    var index;      // used first to initialize pile, then as counter
    var pile = {};  // sock pile

    // start with index = n
    // check that index > 0, then decrement
    // put 2 socks in pile at index
    for(index = n; index--; pile[index] = 2);
    // index is now -1, reuse for counter

    // pick random sock out of pile and decrement its count
    // continue loop if removed sock was not the last
    while(--pile[n * Math.random() | 0]) {
        index++;    // increment counter
    }
    // loop finishes before incrementing counter when first matching pair is removed
    // add 1 to counter to account for initial value of -1
    // add 1 to counter to account for drawing of first matching pair
    return index + 2;
};

4文字を置換f=(n)=>して保存できますn=>(または、割り当てを保持する場合は2 文字、一部を保持する一部を削除する)。
グスタボロドリゲス

良いキャッチ、私はそれを修正しました。ルールで「完全なプログラムまたは関数を記述できます」と読んだとき、それは要件だと思いました。
kamoroso94

3
あたりとしてメタについて合意、名前にバインドされていない無名の機能は、デフォルトでは許容されています。
ズガルブ

これはJavaSockであってはなりませんか?(はい、ラメ)
-gcampbell


2

Pythonの3、142の 105 104バイト

1バイトを節約してくれたEʀɪᴋᴛʜᴇGᴏʟғᴇʀに感謝します!

私の最初の答え:

import random 
i=[x/2 for x in range(int(2*input()))]
d=[]
a=0
random.shuffle(i)
while 1:
 b=i.pop()
 if b in d:
  print(a)
  s
 d=d+[b]
 a+=1

私の新しい答え:

from random import*
i=range(int(input()))*2
shuffle(i)
j=0
for x in i:
 if x in i[:j]:print(1+j)+s
 j+=1

両方ともNameErrorオンで終了しますsます。


2

R、49

N=scan();which(duplicated(sample(rep(1:N,2))))[1]

Rでこれを行うためのより良い方法があるはずです!賢いことをしようとしましたが、うまくいきませんでした。

編集:関数である必要がないため、@ bouncyballによって改善されました。


使用する必要がありますfunction(N)か?使用N=scan();すると2バイト節約されます
弾むボール

1

Python 2、101バイト

from random import*
d=[]
p=range(input())*2
shuffle(p)
while list(set(d))==d:d+=p.pop(),
print len(d)

0

VBA、61バイト

Function K(D):While 2*D-K>K/Rnd:K=K+1:Wend:K=K+1:End Function

-以前に一致が失敗した場合の靴下一致のシフト確率をモデル化します。評価の時点では、Kは「手持ちの靴下」であるため、ドロー数はもう1つです。


0

Pyth、14バイト

lhfnT{T._.S*2S

説明:

       ._        #Start with a list of all prefixes of
         .S      #a randomly shuffled
           *2S   #range from 1 to input (implicit), times 2.
  f              #filter this to only include elements where
   nT{T          #element is not equal to deduplicated self (i.e. it has duplicates)
lh               #print the length of the first element of that filtered list
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.