Simule uma gaveta de meias

16

fundo

Eu tenho uma coleção de "meias para dias úteis", que são sete pares de meias marcadas pelos dias da semana. Quando lavo minhas meias, elas terminam em uma pilha e devo organizá-las nos pares corretos antes de colocá-las no armário. Minha estratégia é puxar uma meia aleatória da pilha de cada vez e colocá-la em uma gaveta. Sempre que há um par de meias na gaveta, amarro-as e coloco-as no armário. Sua tarefa é simular esse processo aleatório e retornar o número de empates necessários para encontrar o primeiro par correspondente.

Entrada

Sua entrada é um número inteiro N ≥ 1 . Ele representa o "número de dias em uma semana": há N pares de meias na pilha e cada par tem um rótulo distinto. Se necessário, você também pode usar uma semente PRNG como entrada.

Resultado

Sua saída é o número de meias que tenho que desenhar antes que o primeiro par correspondente seja encontrado. Por exemplo, se as duas primeiras meias já formarem um par correspondente, a saída será 2.

Obviamente, a saída é aleatória e depende da ordem do desenho. Assumimos que todas as ordens de desenho são igualmente prováveis , de modo que cada vez que uma meia é desenhada, a escolha é uniforme e independente de todas as outras opções.

Exemplo

Vamos N = 3 , para que tenhamos 6 meias no total, rotuladas como AABBCC . Uma possível execução do "protocolo de desenho de meias" é a seguinte:

       | 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

O primeiro par correspondente foi encontrado depois de desenhar o segundo B , que foi a terceira meia a ser desenhada, portanto a saída correta é 3.

Regras e pontuação

Você pode escrever um programa completo ou uma função. A menor contagem de bytes vence e as brechas padrão não são permitidas. A entrada e a saída podem estar em qualquer formato razoável, incluindo unário (sequência de 1s).

Você pode supor que o RNG interno do seu idioma seja perfeito. Você não precisa simular o protocolo de desenho de meias, desde que suas saídas tenham a distribuição de probabilidade correta.

"Casos de teste"

Aqui estão as probabilidades aproximadas de todas as saídas para a entrada 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

Para testar sua solução, você pode executá-la por, digamos, 40.000 vezes e ver se a distribuição de saída está razoavelmente próxima disso.

Zgarb
fonte
25
Vida real, 42 bytes -Draw all socks. End up with an odd number.
AdmBorkBork
Então n = 8 não é igual a 1-> 7 e então 1 novamente? ou seja, 4 meias rotuladas como 1
Viktor Mellgren 03/08
@ViktorMellgren Não, você teria 8 rótulos distintos.
Zgarb 3/08/16
Eu tenho uma gaveta cheia de meias idênticas, então não há necessidade de separá-las.
JDługosz 03/08/19

Respostas:

9

Gelatina , 8 bytes

ḤX€Ṛ<RTḢ

Experimente online! ou verifique a distribuição para N = 7 .

fundo

Seja n o número de pares; existem 2n meias individuais.

Para o primeiro sorteio, existem 2n meias e 0 delas resultariam em um par correspondente. Portanto, a probabilidade de sucesso é 0 / 2n = 0 .

Como o primeiro sorteio não teve sucesso, existem 2n - 1 meias na pilha e 1 delas resultaria em um par correspondente. Portanto, a probabilidade de sucesso é 1 / (2n - 1) .

Se o segundo sorteio não foi bem sucedido, existem 2n - 2 meias na pilha e 2 delas resultariam em um par correspondente. Portanto, a probabilidade de sucesso é 2 / (2n - 2) .

Em geral, se os primeiros k draws não deram certo , há 2n - k meias na pilha e 2 delas resultariam em um par correspondente. Portanto, a probabilidade de sucesso é k / (2n - k) .

Finalmente, se nenhum dos primeiros n empates foi bem-sucedido, existem 2n - k meias na pilha e todas elas resultariam em um par correspondente. Portanto, a probabilidade de sucesso é n / (2n - n) = 1 .

Como funciona

Ḥ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.
Dennis
fonte
8

Gelatina, 8 bytes

Rx2ẊĠṪ€Ṃ

Experimente online!

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

Para verificar, aqui está uma versão que exibe a saída desejada e o resultado da operação "lista aleatória" (para ver em que ordem as meias foram desenhadas).

Maçaneta da porta
fonte
5

Python, 66 bytes

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

Dennis pensou em uma maneira inteligente de reorganizar as coisas, economizando 5 bytes.

Lynn
fonte
4

MATL , 16 15 bytes

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

Experimente online! Ou observe a distribuição empírica para 1000 amostras no N caso = 7 (leva um tempo).

Isso gera diretamente a variável aleatória que representa o resultado, com base em sua distribuição de probabilidade. Seja N o número de pares de meias e p ( k ) denote a probabilidade de que o k -ésimo empate seja bem-sucedido, condicionado ao fato de que o k -ésimo empate não foi bem-sucedido. Então (veja também aqui ):

  • p (1) é obviamente 0. Você não pode ter um par com uma única meia.
  • p (2) é 1 / (2 * N −1). No segundo sorteio, há uma meia vencedora que pode ser escolhida entre 2 * N- 1 meias restantes.
  • p (3) é 2 / (2 * N −2). No terceiro sorteio, existem 2 meias vencedoras em 2 * N −2. O número de meias vencedoras é 2 porque as duas meias que você ganhou após o segundo sorteio eram diferentes.
  • Em geral, pelo mesmo raciocínio, p ( k ) é ( k −1) / (2 * N - k +1)
  • Pela fórmula acima, p ( N +1) é 1. Se você chegar ao N + 1-ésimo empate, é garantido que terá sucesso.

Portanto, o código itera para um máximo de N +1. No k- ésimo sorteio, é gerada uma variável aleatória igual a 1 com probabilidade ( k -1) / (2 * N - k ) ou 0 em caso contrário. Sempre que a variável aleatória é igual a 1 (o sorteio foi bem-sucedido), o processo é interrompido e a corrente k é emitida.

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
Luis Mendo
fonte
1
Você e eu tive a mesma idéia, mas você sabe MATL :)
homem Programa
3

MATL , 14 13 bytes

EZ@G\&=XRafX<

Experimente online! Ou observe a distribuição empírica de 4000 amostras no caso N = 7 (demora um pouco).

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
Luis Mendo
fonte
3

JavaScript, 77 73 bytes

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

Explicação

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;
};
kamoroso94
fonte
Você pode salvar quatro caracteres substituindo f=(n)=>por n=>(ou dois, se desejar manter a tarefa, alguns a mantêm , alguns a removem ).
Gustavo Rodrigues
Boa captura, eu consertei. Embora, quando li "Você pode escrever um programa ou uma função completa" nas regras, pensei que era um requisito.
precisa saber é o seguinte
3
Conforme consenso no Meta , funções sem nome que não estão vinculadas a um nome são aceitáveis ​​por padrão.
Zgarb 2/08/16
Isso não deveria ser JavaSock? (sim, coxo)
gcampbell
2

Python 3, 142 105 104 bytes

Agradecemos a Eʀɪᴋ ᴛʜᴇ Gᴏʟғᴇʀ por salvar um byte!

Minha primeira resposta:

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

Minha nova resposta:

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

Ambos saída com um NameErroron s.

Steven H.
fonte
2

R, 49

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

Tenho certeza de que deve haver uma maneira melhor de fazer isso no R! Eu tentei fazer algo mais inteligente, mas não funcionou.

Edit: Melhorado por @bouncyball, pois não precisa ser uma função.

Solha
fonte
você tem que usar function(N)? usando N=scan();iria salvar 2 bytes
bouncyball
1

Python 2, 101 bytes

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

VBA, 61 bytes

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

- modela a probabilidade de mudança de correspondência de meia, dada a falha anterior na correspondência. No ponto da avaliação, K é "meias na mão", então o número do sorteio é mais um.

Joffan
fonte
0

Pitão, 14 bytes

lhfnT{T._.S*2S

Explicação:

       ._        #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
Cowabunghole
fonte