抽牌后我期望的数字,直到获得ace,2、3等


12

我在解决以下问题时遇到了一些麻烦。

您可以从标准的52张卡片组中抽牌,而无需替换,直到获得一张A。您从剩余的剩余数中提取,直到得到2。继续进行3.整个甲板用完后,您期望的剩余数字是多少?

让它自然

  • Ti=first position of card whose value is i
  • Ui=last position of card whose value is i

因此,问题本质上是要弄清楚当甲板用尽时您将处于的概率k,即:

Pr(T1<<TkUk+1<Tk)

我理解了

Pr(T1<<Tk)=1/k!andPr(Uk+1<Tk)=1/70

但无法再继续下去...


1
如果您在绘制第一张A时已经将所有 s 都绘制了,该怎么办?2
gung-恢复莫妮卡

“预期”数字真的意味着“最可能”数字吗?
ub

这是一个有趣的问题,但是我不确定在“问题本质上等于”之后您所写的数学。在第一句话中,您的意思是写而不是吗?但是,即使那样,我也不确定该说法是否正确。考虑一个序列开始。我们有T 1 = 2 T 2 = 1,所以T 1 > T 2,但是如果我正确地理解了您的文字说明,我们仍然可以在第二个位置选择Ace,然后在第五个位置选择Ace?因此,T 1 < T 2不是必要条件吗?2AAA2T1=2,T2=1T1>T2T1<T2
TooTone 2013年

@TooTone哦,我的意思是像你说的那样,你是对的。T 1 < T 2不是必要条件...T1<T2
法案

@gung在这种情况下,您的甲板将用完,您仍然会在2上。–
法案

Answers:


0

遵循@gung的想法,我相信期望值为5.84?从我对评论的解释来看,我假设“ A”几乎是不可能的值(除非副牌中的最后四张牌都是A)。这是100,000次迭代蒙特卡洛模拟的结果

results
    2     3     4     5     6     7     8     9     J     K     Q     T 
 1406  7740 16309 21241 19998 15127  9393  4906   976   190   380  2334 

如果您想使用它,这里是R代码。

# monte carlo card-drawing functions from here
# http://streaming.stat.iastate.edu/workshops/r-intro/lectures/5-Rprogramming.pdf

# create a straightforward deck of cards
create_deck <-
    function( ){
        suit <- c( "H" , "C" , "D" , "S" )
        rank <- c( "A" , 2:9 , "T" , "J" , "Q" , "K" )
        deck <- NULL
        for ( r in rank ) deck <- c( deck , paste( r , suit ) )
        deck
    }

# construct a function to shuffle everything
shuffle <- function( deck ){ sample( deck , length( deck ) ) }

# draw one card at a time
draw_cards <-
    function( deck , start , n = 1 ){
        cards <- NULL

        for ( i in start:( start + n - 1 ) ){
            if ( i <= length( deck ) ){
                cards <- c( cards , deck[ i ] )
            }
        }

        return( cards )
    }

# create an empty vector for your results
results <- NULL

# run your simulation this many times..
for ( i in seq( 100000 ) ){
    # create a new deck
    sdeck <- shuffle( create_deck() )

    d <- sdeck[ grep('A|2' , sdeck ) ]
    e <- identical( grep( "2" , d ) , 1:4 )

    # loop through ranks in this order
    rank <- c( "A" , 2:9 , "T" , "J" , "Q" , "K" )

    # start at this position
    card.position <- 0

    # start with a blank current.draw
    current.draw <- ""

    # start with a blank current rank
    this.rank <- NULL

    # start with the first rank
    rank.position <- 1

    # keep drawing until you find the rank you wanted
    while( card.position < 52 ){

        # increase the position by one every time
        card.position <- card.position + 1

        # store the current draw for testing next time
        current.draw <- draw_cards( sdeck , card.position )

        # if you draw the current rank, move to the next.
        if ( grepl( rank[ rank.position ] , current.draw ) ) rank.position <- rank.position + 1

        # if you have gone through every rank and are still not out of cards,
        # should it still be a king?  this assumes yes.
        if ( rank.position == length( rank ) ) break        

    }

    # store the rank for this iteration.
    this.rank <- rank[ rank.position ]

    # at the end of the iteration, store the result
    results <- c( results , this.rank )

}

# print the final results
table( results )

# make A, T, J, Q, K numerics
results[ results == 'A' ] <- 1
results[ results == 'T' ] <- 10
results[ results == 'J' ] <- 11
results[ results == 'Q' ] <- 12
results[ results == 'K' ] <- 13
results <- as.numeric( results )

# and here's your expected value after 100,000 simulations.
mean( results )

为什么A不可能?考虑48张牌的顺序,AAAA例如后面的顺序。
TooTone

你是对的..这是一个出270725 -或者与R代码1/prod( 48:1 / 52:5 )
安东尼达米科

1
这个答案是不正确的。考虑“ 2”的计数:因为只有当所有2都在1之前遇到时,才可能出现,因此它的概率是,因此在模拟中的期望值为105/ 8(84)=70用的标准误差37.5。您输出的1660超过了六个标准错误,这几乎肯定是错误的。平均值的准确值(基于106次迭代的不同模拟)为5.833±0.004105/(84)1428.637.516601065.833±0.004
whuber

1
不幸的是,大量记录的代码比所需的时间长和慢了几倍。我证明它的输出不正确;尽管我希望我有时间调试您的代码,但我不是,这样做不是我的任务。我的论据是:只有在所有“ 2”都在所有“ A”之前,并且您仅会在最后使用“ 2”。在种可能的排列四个“ 2”和四个“ A”的方式,恰好其中一个满足此标准。因此,你的价值的标题为“2”下应接近105/70=1429,但事实并非如此。(4+44)=70results105/70=1429
ub

1
甚至主持人也无法删除其他人的投票:-)。卡方检验现在表明您的结果与我的一致,但是很高兴知道您如何测试模拟,因为这样可以提高您对答案的信心。事实上,根据你的第一款在你的答案做了编辑,现在这两个我们的结果是错误的:正如我刚才解释你的问题,这是从未有可能仍然要对一个王牌工作时所有的卡都耗尽。
ub

7

对于仿真,正确和快速至关重要。 这两个目标都建议编写针对编程环境核心功能的代码以及尽可能短而简单的代码,因为简单有助于提高清晰度,而清晰度则可以提高正确性。这是我在以下方面实现两者的尝试R

#
# Simulate one play with a deck of `n` distinct cards in `k` suits.
#
sim <- function(n=13, k=4) {
  deck <- sample(rep(1:n, k)) # Shuffle the deck
  deck <- c(deck, 1:n)        # Add sentinels to terminate the loop
  k <- 0                      # Count the cards searched for
  for (j in 1:n) {
    k <- k+1                          # Count this card
    deck <- deck[-(1:match(j, deck))] # Deal cards until `j` is found
    if (length(deck) < n) break       # Stop when sentinels are reached
  }
  return(k)                   # Return the number of cards searched
}

可以在设置随机数种子之后使用该函数重现的方式应用它replicate,如

> set.seed(17);  system.time(d <- replicate(10^5, sim(13, 4)))
   user  system elapsed 
   5.46    0.00    5.46

这很慢,但是足够快,可以反复进行相当长的(因此很精确)仿真,而无需等待。我们可以通过几种方式展示结果。让我们从其平均值开始:

> n <- length(d)
> mean(d)
[1] 5.83488

> sd(d) / sqrt(n)
[1] 0.005978956

5.8175.853

我们可能还希望查看频率列表(及其标准误差)。以下代码稍微修饰了列表:

u <- table(d)
u.se <- sqrt(u/n * (1-u/n)) / sqrt(n)
cards <- c("A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K")
dimnames(u) <- list(sapply(dimnames(u), function(x) cards[as.integer(x)]))
print(rbind(frequency=u/n, SE=u.se), digits=2)

这是输出:

                2       3      4      5      6      7       8       9       T       J       Q       K
frequency 0.01453 0.07795 0.1637 0.2104 0.1995 0.1509 0.09534 0.04995 0.02249 0.01009 0.00345 0.00173
SE        0.00038 0.00085 0.0012 0.0013 0.0013 0.0011 0.00093 0.00069 0.00047 0.00032 0.00019 0.00013

13n4k

draw <- function(deck) {
  n <- length(sentinels <- sort(unique(deck)))
  deck <- c(deck, sentinels)
  k <- 0
  for (j in sentinels) {
    k <- k+1
    deck <- deck[-(1:match(j, deck))]
    if (length(deck) < n) break
  }
  return(k)
}

(可以draw在任何地方使用sim,但是在开始时draw进行的额外工作使其速度是的两倍sim。)

我们可以通过将其应用于给定套牌的每个不同的随机播放来使用它。由于此处的目的只是一次测试,因此生成这些混洗的效率并不重要。这是一种快速的暴力方式:

n <- 4 # Distinct cards
k <- 2 # Number of suits
d <- expand.grid(lapply(1:(n*k), function(i) 1:n))
e <- apply(d, 1, function(x) var(tabulate(x))==0)
g <- apply(d, 1, function(x) length(unique(x))==n)
d <- d[e & g,]

现在d是一个数据行,其行包含所有混洗。应用于draw每一行并计算结果:

d$result <- apply(as.matrix(d), 1, draw)
    (counts <- table(d$result))

输出(我们将在正式测试中暂时使用)为

   2    3    4 
 420  784 1316 

42021/(2+22)=1/625202520/6=420

sim 10,000n=4k=2

>set.seed(17)
>d.sim <- replicate(10^4, sim(n, k))
>print((rbind(table(d.sim) / length(d.sim), counts / dim(d)[1])), digits=3)

         2     3     4
[1,] 0.168 0.312 0.520
[2,] 0.167 0.311 0.522

> chisq.test(table(d.sim), p=counts / dim(d)[1])

    Chi-squared test for given probabilities

data:  table(d.sim) 
X-squared = 0.2129, df = 2, p-value = 0.899

psimnksimn=13k=4

最后,两个样本的卡方检验将比较的输出与sim另一个答案中报告的输出:

>y <- c(1660,8414,16973,21495,20021,14549,8957,4546,2087,828,313,109)
>chisq.test(cbind(u, y))

data:  cbind(u, y) 
X-squared = 142.2489, df = 11, p-value < 2.2e-16

巨大的卡方统计量得出的p值基本上为零:毫无疑问,sim不同意其他答案。 有两种可能的解决方案:这些答案之一(或两者都有!)不正确,或者它们对问题的理解不同。例如,我将“ 纸牌用完后 ”解释为是指观察最后一张卡之后,如果允许的话,请在终止程序之前更新“您将要使用的号码”。可以想象,最后一步并不是要采取的。也许这种解释上的细微差别可以解释分歧,在这一点上,我们可以修改问题,使问题更清晰。


4

有一个确切的答案(以矩阵乘积的形式,在下面的第4点中给出)。从以下观察中得出,存在一种合理有效的算法来对其进行计算:

  1. N+kNk

  2. 通过仅对ace进行混洗,然后(应用第一个观察结果)将两个,然后三个,等等依次穿插,可以将此问题视为十三步链。

  3. 我们确实需要跟踪的不仅仅是我们所寻找的卡的价值。但是,在执行此操作时,我们不需要考虑标记相对于所有卡的位置而只需考虑其相对于等值或较小值的卡的位置。

    想象一下在第一个王牌上放置一个标记,然后标记在它之后的前两个,依此类推。(如果甲板在任何阶段都没用完而没有显示我们当前正在寻找的牌,我们将不标记所有牌。)让每个标记的“位置”(如果存在)是等于或小于该值的牌数是在标记时(包括标记的卡本身)进行交易的。 这些地方包含所有基本信息。

  4. ith

5.83258855290199651/9

1982600579265894785026945331968939023522542569339917784579447928182134345929899510000000000

这篇文章的其余部分提供了详细信息,在中提供了一个可行的实现R,并以有关问题和解决方案效率的一些评论作为结尾。


生成牌组的随机洗牌

N=k1+k2++kmk1k213(4,4,,4)

NN!=N×(N1)××2×1Nk1k2k1!×k2!××km!

(Nk1,k2,,km)=N!k1!k2!km!,

被称为套牌的“组合”。

k1k1!/k1!=1k1+1k2k1_0k2

_____k1 stars

k2k1+k2(k1+k2k1,k2)=(k1+k2)!k1!k2!

k3((k1+k2)+k3k1+k2,k3)=(k1+k2+k3)!(k1+k2)!k3!k1+k2k1+k2+k3

1×(k1+k2)!k1!k2!×(k1+k2+k3)!(k1+k2)!k3!=(k1+k2+k3)!k1!k2!k3!.

kn(Nk1,k2,,km)

放置过程

k1n=k1+k2++kj1p1nk=kj

_____p1 stars____np stars

pq1n+kpqp+1kq(n+kk)pq

让我们更新该图以反映这种情况:

_____p1 starss stars | ____nps stars

||ssq

jkj1|

τn,k(s,p)=((p1)+jj)((nps)+(kj)1kj1)

|p+s+j+1

  • p
  • s|
  • j
  • |

τn,k(s,p)pq=p+s+j+1sqp

Prn,k(q|p)=(j(p1+jj)(n+kqkj1))/(n+kk)

其中总和始于并结束于。(此总和的可变长度表明存在除非在特殊情况下,否则不太可能是和的函数的封闭公式。)j=max(0,q(n+1))j=min(k1,q(p+1)n,k,q,p

算法

最初存在概率,该位置将是和概率它将具有任何其它可能的值在。这可以由向量。1102,3,,k1p1=(1,0,,0)

散布在下后卡,载体更新为由转换矩阵相乘(在左侧)。重复此过程,直到所有张卡片都已放置。在每个阶段,概率向量条目的总和是某个卡片被标记的机会。因此,使值等于剩余值是在步骤之后没有留下标记的机会p 1 p 2Pr k 1k 2q | p k2p1p2(Prk1,k2(q|p),1pk1,1qk2)k1+k2++kmjpj1j。因此,这些值的连续差异为我们提供了我们找不到要标记的类型的牌的可能性:即当游戏结束时牌组耗尽时,我们正在寻找的牌的值的概率分布。j


实作

以下R代码实现了该算法。它与前面的讨论类似。首先,转换概率的计算方式为t.matrix(无需通过除法进行归一化,从而更容易在测试代码时跟踪计算结果):(n+kk)

t.matrix <- function(q, p, n, k) {
  j <- max(0, q-(n+1)):min(k-1, q-(p+1))
  return (sum(choose(p-1+j,j) * choose(n+k-q, k-1-j))
}

用来transition将更新为。它计算转换矩阵并执行乘法。如果参数为空向量,它还将负责计算初始向量:pj1pjp1p

#
# `p` is the place distribution: p[i] is the chance the place is `i`.
#
transition <- function(p, k) {
  n <- length(p)
  if (n==0) {
    q <- c(1, rep(0, k-1))
  } else {
    #
    # Construct the transition matrix.
    #
    t.mat <- matrix(0, nrow=n, ncol=(n+k))
    #dimnames(t.mat) <- list(p=1:n, q=1:(n+k))
    for (i in 1:n) {
      t.mat[i, ] <- c(rep(0, i), sapply((i+1):(n+k), 
                                        function(q) t.matrix(q, i, n, k)))
    }
    #
    # Normalize and apply the transition matrix.
    #
    q <- as.vector(p %*% t.mat / choose(n+k, k))
  }
  names(q) <- 1:(n+k)
  return (q)
}

现在,我们可以轻松地计算任何牌组在每个阶段的非标记概率:

#
# `k` is an array giving the numbers of each card in order;
# e.g., k = rep(4, 13) for a standard deck.
#
# NB: the *complements* of the p-vectors are output.
#
game <- function(k) {
  p <- numeric(0)
  q <- sapply(k, function(i) 1 - sum(p <<- transition(p, i)))
  names(q) <- names(k)
  return (q)
}

它们是标准卡座的:

k <- rep(4, 13)
names(k) <- c("A", 2:9, "T", "J", "Q", "K")
(g <- game(k))

输出是

         A          2          3          4          5          6          7          8          9          T          J          Q          K 
0.00000000 0.01428571 0.09232323 0.25595013 0.46786622 0.66819134 0.81821790 0.91160622 0.96146102 0.98479430 0.99452614 0.99818922 0.99944610

根据规则,如果标记了国王,那么我们将不再寻找其他牌:这意味着必须将的值增加到。这样做后,差异将得出“甲板用尽时将要使用的数字”的分布:0.99944611

> g[13] <- 1; diff(g)
          2           3           4           5           6           7           8           9           T           J           Q           K 
0.014285714 0.078037518 0.163626897 0.211916093 0.200325120 0.150026562 0.093388313 0.049854807 0.023333275 0.009731843 0.003663077 0.001810781

(将其与我在另一个描述蒙特卡洛模拟的答案中报告的输出进行比较:它们看起来是相同的,直到预期的随机变化量为止。)

期望值是立即的:

> sum(diff(g) * 2:13)
[1] 5.832589

总而言之,这只需要十几行左右的可执行代码。我已经根据手工计算检查了较小值(最多)。因此,如果代码与问题的先前分析之间出现明显差异,请信任该代码(因为分析可能存在印刷错误)。k3


备注

与其他序列的关系

当每张卡中都有一张时,分布是整数的倒数序列:

> 1/diff(game(rep(1,10)))
[1]      2      3      8     30    144    840   5760  45360 403200

在地方的价值就是(从处开始)。这是在线整数序列大全中的序列A001048。因此,我们可能希望有一个常数为的甲板(“适合的”甲板)的封闭公式来推广该序列,该序列本身具有深远的意义。(例如,它计算置换组中最大共轭类的大小,并且还与三项式系数有关。)(不幸的是,的一般化中的倒数通常不是整数。)ii!+(i1)!i=1kik>1

游戏是随机过程

我们的分析清楚地表明最初的的矢量的系数,,是恒定的。例如,让我们跟踪处理每组卡时的输出:ipjjigame

> sapply(1:13, function(i) game(rep(4,i)))

[[1]]
[1] 0

[[2]]
[1] 0.00000000 0.01428571

[[3]]
[1] 0.00000000 0.01428571 0.09232323

[[4]]
[1] 0.00000000 0.01428571 0.09232323 0.25595013

...

[[13]]
 [1] 0.00000000 0.01428571 0.09232323 0.25595013 0.46786622 0.66819134 0.81821790 0.91160622 0.96146102 0.98479430 0.99452614 0.99818922 0.99944610

例如,最终向量的第二个值(描述了52张牌的完整结果)已经在第二组处理之后出现(等于)。因此,如果只需要有关通过卡值进行的标记的信息则只需对一副张卡进行计算。1/(84)=1/70jthk1+k2++kj

由于随着增加,没有标记价值的牌的机会很快就接近,因此在四套衣服中有种类型的牌之后,我们几乎达到了预期的极限值。确实,极限值大约为(对于张张牌计算,这时双精度舍入误差会阻止进一步的运算)。j1j135.8333554×32

定时

查看应用于向量,我们看到其时序应与成比例,并且-使用粗略上限-与与成比例不差。通过对到和到所有计算进行计时,并仅分析花费较长时间(秒或更长时间)的计算,我估计计算时间约为,支持此上限评估。ķ ķ ... ķ ķ 2 3 ķ = 1 7 Ñ = 10 30 1 / 2 ø ķ 2 Ñ 2.9m(k,k,,k)k2m3k=17n=10301/2O(k2n2.9)

这些渐近线的一种用途是预测较大问题的计算时间。例如,看到情况大约需要秒,我们可以估计,(非常有趣)情况大约需要秒。(实际上需要秒。)1.31 ķ = 1 Ñ = 100 1.31 1 / 4 2100 / 30 2.92.7 2.87k=4,n=301.31k=1,n=1001.31(1/4)2(100/30)2.92.72.87


0

5.8329

#!/usr/bin/perl

use strict;

my @deck = (1..13) x 4;

my $N = 100000; # Monte Carlo iterations.

my $mean = 0;

for (my $i = 1; $i <= $N; $i++) {
    my @d = @deck;
    fisher_yates_shuffle(\@d);
    my $last = 0;
        foreach my $c (@d) {
        if ($c == $last + 1) { $last = $c }
    }
    $mean += ($last + 1) / $N;
}

print $mean, "\n";

sub fisher_yates_shuffle {
    my $array = shift;
        my $i = @$array;
        while (--$i) {
        my $j = int rand($i + 1);
        @$array[$i, $j] = @$array[$j, $i];
    }
}

鉴于此答案与所有​​先前答案(包括两个模拟和一个理论(精确)答案)之间存在巨大差异,我怀疑您在以不同的方式解释该问题。在您没有任何解释的情况下,我们仅需将其视为错误。(我怀疑您可能会少数一数,在这种情况下,您的4.8应该与5.83258进行比较...;但是即使那样,您的两位有效数字也无法进一步解决这个问题。)
笨蛋

1
是的 有一个错误的错误。
2013年
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.