Имитировать ящик носка


16

Фон

У меня есть коллекция «носков дня недели», которые представляют собой семь пар носков, помеченных по дням недели. Когда я стираю свои носки, они оказываются в куче, и я должен расположить их в правильные пары, прежде чем положить их в шкаф. Моя стратегия - вытащить один случайный носок из кучи за раз и положить его в ящик. Всякий раз, когда на ящике есть подходящая пара носков, я связываю их и кладу в шкаф. Ваша задача - смоделировать этот случайный процесс и вернуть количество розыгрышей, необходимое для поиска первой подходящей пары.

вход

Ваш ввод - целое число N ≥ 1 . Он представляет собой «количество дней в неделе»: в стопке N пар носков, и каждая пара имеет свою метку. При необходимости вы также можете использовать начальное значение PRNG.

Выход

Ваш вывод - это количество носков, которые я должен нарисовать до того, как будет найдена первая подходящая пара. Например, если первые два носка уже образуют совпадающую пару, вывод будет 2.

Конечно, вывод является случайным и зависит от порядка рисования. Мы предполагаем, что все порядки отрисовки одинаково вероятны , поэтому каждый раз, когда рисуется носок, выбор является равномерным и независимым от всех других вариантов.

пример

Пусть N = 3 , так что у нас всего 6 носков, помеченных AABBCC . Один из возможных вариантов «протокола рисования носков» выглядит следующим образом:

       | 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

Первая подходящая пара была найдена после рисования второго B , который был третьим носком, который нужно нарисовать, поэтому правильный вывод 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
Реальная жизнь, 42 байта -Draw all socks. End up with an odd number.
AdmBorkBork


Значит, n = 8 не равно 1-> 7, а затем снова 1? т.е. 4
носка с

@ViktorMellgren Нет, у вас будет 8 разных ярлыков.
Згарб

У меня есть ящик, полный одинаковых носков, поэтому мне не нужно их перебирать.
JDługosz

Ответы:


9

Желе , 8 байт

ḤX€Ṛ<RTḢ

Попробуйте онлайн! или проверьте распределение для N = 7 .

Фон

Пусть n будет количеством пар; Есть 2n отдельных носков.

Для первого розыгрыша есть 2n носков, и 0 из них приведут к совпадающей паре. Следовательно, вероятность успеха 0 / 2n = 0 .

Так как первый розыгрыш не был успешным, есть 2n - 1 на стопке носков, и один из них приведет к соответствующей паре. Следовательно, вероятность успеха равна 1 / (2n - 1) .

Если второй розыгрыш не был успешным, есть на стопке 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

MATL , 16 15 байт

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

Попробуйте онлайн! Или наблюдайте эмпирическое распределение для 1000 образцов в случае N = 7 (это занимает некоторое время).

Это непосредственно генерирует случайную величину, представляющую результат, основанную на ее распределении вероятностей. Пусть N будет число пар носков, и пусть р ( К ) обозначает вероятность того, что K -го Жеребьевка прошла успешно, обусловлено тем , что к -1-й розыгрыш не был успешным. Тогда (см. Также здесь ):

  • p (1), очевидно, 0. Вы не можете иметь пару с одним носком.
  • p (2) равно 1 / (2 * N -1). На втором розыгрыше есть один выигрышный носок, который можно выбрать из 2 * N -1 оставшихся носков.
  • p (3) равно 2 / (2 * N − 2). На третьем розыгрыше есть 2 победных носка из 2 * N − 2. Количество выигрышных носков равно 2, потому что два носка, которые вы получили после второго розыгрыша, были разными.
  • В общем, по тем же соображениям, p ( k ) равно ( k −1) / (2 * N - k +1)
  • По приведенной выше формуле p ( N + 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

MATL , 14 13 байт

EZ@G\&=XRafX<

Попробуйте онлайн! Или соблюдайте эмпирическое распределение для 4000 выборок в случае N = 7 (это занимает некоторое время).

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;
};

Вы можете сохранить четыре символа замены f=(n)=>с n=>(или два, если вы хотите сохранить задание, некоторые держать его , некоторые удалить его ).
Густаво Родригес

Хороший улов, я исправил это. Хотя, когда я прочитал в правилах «Вы можете написать полную программу или функцию», я подумал, что это требование.
kamoroso94

3
Согласно консенсусу по Meta , неназванные функции, которые не связаны с именем, являются приемлемыми по умолчанию.
Згарб

Разве это не должен быть JavaSock? (да,
отстой


2

Python 3, 142 105 104 байта

Благодаря 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

Р, 49

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

Я уверен, что должен быть лучший способ сделать это в R! Я пытался сделать что-то умнее, но это не сработало.

Редактировать: Улучшено @bouncyball, так как оно не должно быть функцией.


ты должен использовать function(N)? использование N=scan();спасло бы 2 байта
bouncyball

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 - это «носки в руке», поэтому номер тиража - еще один.


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.