จำลองลิ้นชักถุงเท้า


16

พื้นหลัง

ฉันมีชุด "ถุงเท้าวันทำงาน" ซึ่งเป็นถุงเท้าเจ็ดคู่ที่ติดป้ายชื่อโดยวันในสัปดาห์ เมื่อฉันล้างถุงเท้าของพวกเขาพวกเขาจบลงด้วยกองและฉันต้องจัดให้พวกเขาเป็นคู่ที่ถูกต้องก่อนที่จะนำพวกเขาเข้าไปในตู้เสื้อผ้า กลยุทธ์ของฉันคือดึงถุงเท้าแบบสุ่มหนึ่งอันออกจากกองพร้อมกันแล้ววางลงบนลิ้นชัก เมื่อใดก็ตามที่มีถุงเท้าคู่ที่ตรงกันบนลิ้นชักฉันผูกพวกเขาเข้าด้วยกันและวางไว้ในตู้เสื้อผ้า งานของคุณคือการจำลองกระบวนการสุ่มนี้และคืนจำนวนการจับที่ต้องการเพื่อหาคู่แรกที่จับคู่

อินพุต

ข้อมูลของคุณเป็นจำนวนเต็มN ≥ 1 มันหมายถึง "จำนวนวันในหนึ่งสัปดาห์": มีNคู่ของถุงเท้าในกองและแต่ละคู่มีป้ายชื่อที่แตกต่างกัน หากจำเป็นคุณอาจใช้เมล็ดพันธุ์ PRNG เป็นอินพุตได้

เอาท์พุต

ผลลัพธ์ของคุณคือจำนวนถุงเท้าที่ฉันต้องวาดก่อนที่จะพบคู่แรกที่ตรงกัน 2ตัวอย่างเช่นถ้าทั้งสองถุงเท้าแรกแล้วแบบคู่จับคู่ออกเป็น

แน่นอนว่าผลลัพธ์เป็นแบบสุ่มและขึ้นอยู่กับลำดับการวาด เราคิดว่าคำสั่งซื้อรูปวาดทั้งหมดมีโอกาสเท่ากันดังนั้นในแต่ละครั้งที่มีการดึงถุงเท้าตัวเลือกจะเหมือนกันและเป็นอิสระจากตัวเลือกอื่น ๆ ทั้งหมด

ตัวอย่าง

ให้N = 3 , เพื่อให้เรามี 6 ถุงเท้ารวมป้ายAABBCC หนึ่งในการทำงานที่เป็นไปได้ของ "sock-drawing protocol" มีดังต่อไปนี้:

       | 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

ทั้งคู่จับคู่เป็นครั้งแรกที่พบว่าหลังจากการวาดภาพที่สองB3ซึ่งเป็นถุงเท้าที่สามที่จะวาดเพื่อการส่งออกที่ถูกต้องคือ

กฎและการให้คะแนน

คุณสามารถเขียนโปรแกรมเต็มรูปแบบหรือฟังก์ชั่น จำนวนไบต์ต่ำสุดที่ชนะและช่องโหว่มาตรฐานไม่ได้รับอนุญาต อินพุตและเอาต์พุตสามารถอยู่ในรูปแบบที่เหมาะสมรวมถึง unary (สตริงจำนวน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 ถุงเท้าที่มีป้ายกำกับ 1
Viktor Mellgren

@ViktorMellgren ไม่คุณจะมี 8 ป้ายกำกับที่แตกต่างกัน
Zgarb

ฉันมีลิ้นชักที่เต็มไปด้วยถุงเท้าที่เหมือนกันดังนั้นไม่จำเป็นต้องเรียงผ่านพวกเขา
JDługosz

คำตอบ:


9

เยลลี่ 8 ไบต์

ḤX€Ṛ<RTḢ

ลองออนไลน์! หรือตรวจสอบการกระจายสำหรับN = 7

พื้นหลัง

ให้nเป็นจำนวนคู่ มีถุงเท้าละ2n

สำหรับการจับครั้งแรกมี ถุงเท้า2nและ0ของพวกเขาจะทำให้คู่ที่ตรงกัน ดังนั้นความน่าจะเป็นของความสำเร็จคือ0 / 2n = 0

ตั้งแต่การจับสลากครั้งแรกไม่ประสบความสำเร็จ ถุงเท้า2n - 1อยู่บนกองและ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-/<?@.

ลองออนไลน์! หรือสังเกตการกระจายเชิงประจักษ์สำหรับ 1,000 ตัวอย่างในกรณีN = 7 (ใช้เวลาสักครู่)

สิ่งนี้จะสร้างตัวแปรสุ่มที่แสดงผลลัพธ์โดยตรงโดยขึ้นอยู่กับการแจกแจงความน่าจะเป็น ให้Nเป็นจำนวนคู่ถุงเท้าและให้p ( k ) แสดงถึงความน่าจะเป็นที่การดึงk- th นั้นประสบความสำเร็จโดยมีเงื่อนไขว่าการดึงK -1 นั้นไม่ประสบความสำเร็จ จากนั้น (ดูเพิ่มเติมที่ที่นี่ ):

  • พี (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 -th เสมอตัวแปรสุ่มจะถูกสร้างขึ้นซึ่งเท่ากับ 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<

ลองออนไลน์! หรือสังเกตการกระจายเชิงประจักษ์สำหรับตัวอย่าง 4,000 ตัวอย่างในกรณี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=>(หรือสองถ้าคุณต้องการที่จะเก็บงานให้บางส่วนเก็บไว้ , ลบบางอย่างมัน )
Gustavo Rodrigues

เยี่ยมมากฉันได้ซ่อมแล้ว แม้ว่าเมื่อฉันอ่าน "คุณสามารถเขียนโปรแกรมหรือฟังก์ชั่นเต็มรูปแบบ" ในกฎฉันคิดว่ามันเป็นข้อกำหนด
kamoroso94

3
ตามฉันทามติบน Metaฟังก์ชั่นที่ไม่มีชื่อที่ไม่ได้ผูกไว้กับชื่อนั้นเป็นที่ยอมรับโดยค่าเริ่มต้น
Zgarb

นี่ไม่ควรเป็น JavaSock ใช่ไหม (ใช่ง่อย)
gcampbell


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

ทั้งสองออกจากที่มีในNameErrors


2

R, 49

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

ฉันแน่ใจว่าต้องมีวิธีที่ดีกว่าในการทำเช่นนี้ใน R! ฉันพยายามทำสิ่งที่ฉลาดกว่า แต่ก็ไม่ได้ผล

แก้ไข: ปรับปรุงโดย @bouncyball เนื่องจากไม่จำเป็นต้องมีฟังก์ชั่น


คุณต้องใช้function(N)ไหม การใช้N=scan();จะช่วยประหยัด 2 ไบต์
bouncyball


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.