模拟袜子抽屉


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之后找到第一对匹配项,第二对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个标记为1的袜子
Viktor Mellgren

@ViktorMellgren不,您将有8个不同的标签。
Zgarb

我的抽屉里装满了相同的袜子,因此无需对它们进行分类。
JDługosz

Answers:


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袜子,其中对将产生配对。因此,成功的概率为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。你不能有一对袜子。
  • p(2)是1 /(2 * N -1)。在第二次抽签中,可以从剩余的2 * N -1个袜子中选择一只获胜的袜子。
  • p(3)是2 /(2 * N -2)。在第三次抽签中,在2 * N -2中有2支获胜的袜子。获胜的袜子数为2,因为第二次抽奖后得到的两只袜子是不同的。
  • 通常,基于相同的理由,pk)为(k -1)/(2 * N - k +1)
  • 通过以上公式,pN +1)为1。如果您获得第N +1次抽奖,则可以保证成功。

因此,代码最多可重复进行N +1次抽奖。在第k次绘制时,将生成一个随机变量,其概率为(k -1)/(2 * N - k)等于1 ,否则为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;
};

您可以保存四个字符替换f=(n)=>n=>(或两个,如果你想保留的分配,一些保持它一些将其删除)。
古斯塔沃·罗德里格斯

不错,我已经解决了。虽然,当我在规则中阅读“您可以编写完整的程序或函数”时,我认为这是必要条件。
kamoroso94 '16

3
根据对Meta的共识,默认情况下可接受未绑定到名称的未命名函数。
Zgarb

这不是JavaSock吗?(是的,
me子


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

两者都以NameErroron 退出s


2

R,49

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

我敢肯定,在R中一定有更好的方法!我尝试做一些聪明的事情,但是没有用。

编辑:通过@bouncyball进行了改进,因为它不一定是一个函数。


你必须使用function(N)吗?使用N=scan();将节省2个字节
bouncyball '16

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.