Mô phỏng ngăn kéo vớ


16

Lý lịch

Tôi có một bộ sưu tập "vớ ngày thường", đó là bảy đôi vớ được dán nhãn theo các ngày trong tuần. Khi tôi giặt tất, chúng sẽ thành một đống, và tôi phải sắp xếp chúng thành các cặp chính xác trước khi cất chúng vào tủ. Chiến lược của tôi là kéo một chiếc tất ngẫu nhiên từ đống đồ một lúc và đặt nó vào ngăn kéo. Bất cứ khi nào có một đôi vớ phù hợp trên ngăn kéo, tôi buộc chúng lại với nhau và cất chúng vào tủ. Nhiệm vụ của bạn là mô phỏng quá trình ngẫu nhiên này và trả về số lần rút cần thiết để tìm cặp phù hợp đầu tiên.

Đầu vào

Đầu vào của bạn là số nguyên N 1 . Nó đại diện cho "số ngày trong một tuần": có N đôi vớ trong đống và mỗi đôi có một nhãn riêng. Nếu cần thiết, bạn cũng có thể lấy hạt giống PRNG làm đầu vào.

Đầu ra

Đầu ra của bạn là số vớ tôi phải rút trước khi tìm thấy cặp phù hợp đầu tiên. Ví dụ: nếu hai chiếc vớ đầu tiên đã tạo thành một cặp phù hợp, thì đầu ra là 2.

Tất nhiên, đầu ra là ngẫu nhiên, và phụ thuộc vào thứ tự vẽ. Chúng tôi giả định rằng tất cả các đơn đặt hàng bản vẽ đều có khả năng như nhau , do đó, mỗi lần rút một chiếc tất, sự lựa chọn là thống nhất và độc lập với tất cả các lựa chọn khác.

Thí dụ

Đặt N = 3 , để chúng ta có tổng cộng 6 vớ, được dán nhãn AABBCC . Một lần chạy có thể của "giao thức vẽ sock" như sau:

       | 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

Cặp kết hợp đầu tiên được tìm thấy sau khi vẽ B thứ hai , đó là cặp thứ ba được vẽ, do đó, đầu ra chính xác là 3.

Quy tắc và tính điểm

Bạn có thể viết một chương trình đầy đủ hoặc một chức năng. Số byte thấp nhất sẽ thắng và các sơ hở tiêu chuẩn không được phép. Đầu vào và đầu ra có thể ở bất kỳ định dạng hợp lý nào, bao gồm cả unary (chuỗi 1s).

Bạn có thể cho rằng RNG tích hợp ngôn ngữ của bạn là hoàn hảo. Bạn không thực sự phải mô phỏng giao thức vẽ sock, miễn là đầu ra của bạn có phân phối xác suất chính xác.

"Các trường hợp thử nghiệm"

Dưới đây là xác suất gần đúng của tất cả các đầu ra cho đầu vào 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

Để kiểm tra giải pháp của bạn, bạn có thể chạy nó, giả sử, 40 000 lần và xem liệu phân phối đầu ra có hợp lý gần với điều này không.


25
Cuộc sống thực, 42 byte -Draw all socks. End up with an odd number.
admBorkBork


Vậy n = 8 không bằng 1-> 7 rồi 1 lần nữa? tức là 4 chiếc vớ có nhãn 1
Viktor Mellgren

@ViktorMellgren Không, bạn sẽ có 8 nhãn riêng biệt.
Zgarb

Tôi có một ngăn kéo đầy vớ giống hệt nhau, vì vậy không cần phải sắp xếp chúng.
JDługosz

Câu trả lời:


9

Thạch , 8 byte

ḤX€Ṛ<RTḢ

Hãy thử trực tuyến! hoặc xác minh phân phối cho N = 7 .

Lý lịch

Gọi n là số cặp; Có 2n vớ cá nhân.

Đối với lần rút đầu tiên, có 2n vớ và 0 trong số đó sẽ dẫn đến một cặp phù hợp. Do đó, xác suất thành công là 0 / 2n = 0 .

Vì lần rút thăm đầu tiên không thành công, có 2n - 1 vớ trên cọc và 1 trong số đó sẽ dẫn đến một cặp phù hợp. Do đó, xác suất thành công là 1 / (2n - 1) .

Nếu lần rút thứ hai không thành công, có 2n - 2 vớ trên cọc và 2 trong số đó sẽ dẫn đến một cặp phù hợp. Do đó, xác suất thành công là 2 / (2n - 2) .

Nói chung, nếu lần rút k đầu tiên không thành công, có 2n - k vớ trên cọc và 2 trong số đó sẽ dẫn đến một cặp phù hợp. Do đó, xác suất thành công là k / (2n - k) .

Cuối cùng, nếu không có lần rút n đầu tiên nào thành công, có 2n - k vớ trên cọc và tất cả chúng sẽ dẫn đến một cặp phù hợp. Do đó, xác suất thành công là n / (2n - n) = 1 .

Làm thế nào nó hoạt động

Ḥ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

Thạch, 8 byte

Rx2ẊĠṪ€Ṃ

Hãy thử trực tuyến!

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

Để xác minh, đây là phiên bản hiển thị cả đầu ra mong muốn và kết quả của hoạt động "danh sách xáo trộn" (để xem những gì vớ được rút ra).


5

Python, 66 byte

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

Dennis nghĩ ra một cách thông minh để sắp xếp lại mọi thứ, tiết kiệm 5 byte.


4

MATL , 16 15 byte

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

Hãy thử trực tuyến! Hoặc quan sát phân phối theo kinh nghiệm cho 1000 mẫu trong trường hợp N = 7 (phải mất một lúc).

Điều này trực tiếp tạo ra biến ngẫu nhiên đại diện cho kết quả, dựa trên phân phối xác suất của nó. Gọi N là số cặp sock và để p ( k ) biểu thị xác suất rút thăm thứ k thành công, dựa trên thực tế là lần rút k -1 không thành công. Sau đó (xem thêm tại đây ):

  • p (1) rõ ràng là 0. Bạn không thể có một cặp với một chiếc tất.
  • p (2) là 1 / (2 * N 1). Ở lần rút thứ hai, có một chiếc vớ chiến thắng có thể được chọn trong số 2 * N 1 vớ còn lại.
  • p (3) là 2 / (2 * N 2). Ở lần rút thứ ba, có 2 chiếc vớ chiến thắng trong số 2 * N 2. Số lượng vớ chiến thắng là 2 vì hai vớ bạn nhận được sau lần rút thứ hai là khác nhau.
  • Nói chung, theo cùng một lý do, p ( k ) là ( k 1) / (2 * N - k +1)
  • Theo công thức trên, p ( N +1) là 1. Nếu bạn đạt được kết quả hòa N + 1, bạn được đảm bảo thành công sau đó.

Vì vậy, mã lặp lại cho tối đa N +1 rút ra. Tại k -th vẽ một biến ngẫu nhiên được tạo bằng 1 với xác suất ( k -1) / (2 * N - k ) hoặc 0 nếu không. Bất cứ khi nào biến ngẫu nhiên bằng 1 (rút thăm đã thành công) thì quá trình dừng lại và k hiện tại là đầu ra.

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
Bạn và tôi có cùng một ý tưởng, nhưng bạn biết MATL :)
Người đàn ông chương trình

3

MATL , 14 13 byte

EZ@G\&=XRafX<

Hãy thử trực tuyến! Hoặc quan sát phân phối theo kinh nghiệm cho 4000 mẫu trong trường hợp N = 7 (phải mất một lúc).

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 byte

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

Giải trình

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

Bạn có thể lưu bốn ký tự thay thế f=(n)=>bằng n=>(hoặc hai, nếu bạn muốn giữ bài tập, một số giữ nó , một số xóa nó ).
Gustavo Coleues

Bắt tốt, tôi đã sửa nó. Mặc dù, khi tôi đọc "Bạn có thể viết một chương trình đầy đủ hoặc một chức năng" trong các quy tắc, tôi nghĩ đó là một yêu cầu.
kamoroso94

3
Theo sự đồng thuận trên Meta , các hàm không tên không bị ràng buộc với tên được mặc định chấp nhận.
Zgarb

Đây có phải là JavaSock không? (vâng, khập khiễng)
gcampbell


2

Python 3, 142 105 104 byte

Cảm ơn Eʀɪᴋ Gᴏʟғᴇʀ vì đã tiết kiệm một byte!

Câu trả lời đầu tiên của tôi:

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

Câu trả lời mới của tôi:

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

Cả hai thoát với một NameErrorbật s.


2

R, 49

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

Tôi chắc chắn phải có cách tốt hơn để làm điều này trong R! Tôi đã thử làm một cái gì đó thông minh hơn nhưng nó không hoạt động.

Chỉnh sửa: Được cải thiện bởi @bouncyball vì nó không phải là một chức năng.


bạn có phải sử dụng function(N)không sử dụng N=scan();sẽ tiết kiệm 2 byte
bouncyball

1

Python 2, 101 byte

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

0

VBA, 61 byte

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

- mô hình xác suất dịch chuyển của sock match do không khớp trước đó. Tại thời điểm đánh giá, K là "vớ trong tay", do đó, rút ​​số là một.


0

Bình thường, 14 byte

lhfnT{T._.S*2S

Giải trình:

       ._        #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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.