从赶地铁到数学建模:刚好赶上和刚好错过的概率
原创 · 约 19 分钟阅读 · 阅读 --

从赶地铁到数学建模:刚好赶上和刚好错过的概率

作者: Alex Xiang


古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。更完整的更新写在微信公众号「字与码」:工作经历、对新技术的想法,以及这些年走弯路的记录,会不定期发在那里。若觉得博客对你有用,欢迎顺手关注。

连续四个周六早上,我都差一点赶上地铁 18 号线,又都眼睁睁看着它关门开走。

那个连续四次“就差一点”的人,就是我。

本来这只是一个很普通的通勤小崩溃。但把概率算出来之后,我突然觉得这事不太普通了:如果一个人能连续四次踩进这么窄的倒霉窗口,这个概率低到足够让我认真考虑一下,是不是该顺路去买张彩票。

有些小事很适合拿来练数学建模,尤其是这种发生在自己身上的小事。

比如周六早上 9 点左右去坐地铁 18 号线。如果发车间隔大约 10 分钟,列车在站台停 30 秒,人跑步速度按每秒 3 米算,那么一个乘客“刚好赶上车”的概率有多大?如果连续 4 次都赶上,又有多夸张?

反过来,如果列车关门的那一刻,人已经冲到离列车 50 米以内,但还是没赶上,这种“非常倒霉”的概率又是多少?连续 4 次都这么倒霉,是不是已经可以拿来讲故事?

先把最小模型的结论放前面。看完这张表,再回头想“连续四个周六都差一点没赶上”,就知道为什么我会想到买彩票了。

问题概率
单次赶上车5%
连续 4 次都赶上0.000625%,约 16 万分之一
单次非常倒霉2.78%
连续 4 次都非常倒霉0.0000595%,约 168 万分之一

这几个数不是拍脑袋,而是一个很标准的“时间窗口 / 总周期”模型。

但这也正是这道题最有意思的地方:如果只按题目给出的信息计算,它非常简单;如果把“人距离车门多远”“从哪个入口进站”“跑步路径是否通畅”都放进模型,它马上就会变成一个带空间分布的概率模型,甚至会用到积分。

所以这篇文章不只算一个数,而是把这个问题当成一个小型数学建模案例:先做最小模型,再讨论模型怎么升级。

原始 Prompt

这篇文章来自下面这个问题。我把原始指令也放出来,方便以后复盘 Codex 是怎么把自然语言问题变成可计算模型的。

需要解决一个数学问题:假设每周六早上9点左右地铁18号线的发车间隔是10分钟,列车在站台上停车时间为30秒,如果乘客在这30秒内位于能够跑步达到车内的距离,就认为乘客能赶上车,人的跑步速度假设为每秒3米,帮我计算这个时间点赶上18号线地铁的概率,连续4次都能赶上的概率是多少。另一个问题,同样的假设,如果乘客在列车关门的这一刻,正好位于距离列车50米之内的距离而没能赶上列车,认为这个乘客是非常倒霉,计算一下非常倒霉的概率,再计算一下连续四次倒霉的概率。整个分析和计算结果生成一篇博客文章,包括输入给codex的prompt指令。

从自然语言到数学模型

题目里给了三个数字:

  • 发车间隔:10 分钟,也就是 600 秒;
  • 停车时间:30 秒;
  • 跑步速度:3 米/秒。

题目还给了一个判断规则:如果乘客在列车停站的 30 秒内,位于能够跑步达到车内的距离,就认为能赶上。

这句话里其实藏着两个变量。

第一个变量是时间:乘客是在列车开门后的第几秒到达可奔跑区域的?

第二个变量是距离:这一刻,他离能进车厢的位置还有多远?

写成符号,可以这样定义:

H = 600 秒        发车周期
S = 30 秒         停站开门时间
v = 3 米/秒       跑步速度
D = 50 米         “非常倒霉”的距离阈值
T = 乘客到达时刻在一个发车周期内的位置
X = 乘客到达时离车门的距离

这样一来,“能赶上”不是一句口语判断,而是一个不等式:

0 <= T <= S
并且
X <= v × (S - T)

意思是:你必须在车门还开着的时候到达,而且剩下的开门时间足够你跑完剩余距离。

“非常倒霉”也可以写成一个窗口:车门已经关了,但按 3 米/秒折算,你离车门不到 50 米,也就是只晚了不到 16.67 秒。

0 < T - S <= D / v

在这一步,问题已经从生活描述变成了一个概率模型。

最小模型:先只看时间

换成人话,就是你不是掐着点来的,也不是每次都看实时到站信息,而是把你到站台附近的时间看成落在一个 600 秒周期里的随机点。

最小模型做两个简化。

第一,只看时间,不细分站台空间。也就是说,只要乘客落在 30 秒开门窗口里,就认为他已经在可跑进车厢的范围内。

第二,乘客到达时间在 600 秒周期内均匀分布。也就是每一秒到达的可能性一样。

这个假设会让问题变得很干净:概率就是“能赶上的时间窗口”除以“总发车周期”。

如果要算更真实的概率,还需要更多信息,比如站台长度、入口到车门的距离、乘客通常从哪个口进站、人在站台上出现的位置分布、是否有楼梯电梯阻挡、是否允许跑、列车是否准点。这些题目没有给,所以这篇文章不编这些变量。

这也是建模时很重要的一点:题目没有给的信息,不要假装知道。可以列为模型扩展,但不要塞进最小模型里硬算。

会不会用到微积分

最小模型不需要微积分。它只需要除法:

概率 = 有利时间窗口 / 总时间窗口

但如果我们把距离变量 X 也放进去,就会自然出现积分。

在更完整的模型里,乘客到达时间 T 在 0 到 600 秒之间随机,距离 X 也有自己的分布。赶上车的条件是:

0 <= T <= S
X <= v × (S - T)

如果用 F_X(x) 表示距离 X 的累积分布函数,也就是“距离不超过 x 的概率”,那么赶上车的概率可以写成:

P(赶上) = (1 / H) × ∫[0 到 S] F_X(v × (S - t)) dt

这就是一个积分。

它表达的意思并不玄:在开门后的每一秒,都看看“剩余时间还能跑多远”,再计算有多少乘客处在这个距离以内,最后把这些可能性沿着 30 秒开门时间加起来。

如果我们进一步假设 X 在 0 到 L 米之间均匀分布,而且 L 大于 90 米,那么:

F_X(x) = x / L
P(赶上) = (1 / H) × ∫[0 到 S] v × (S - t) / L dt
       = v × S^2 / (2 × L × H)

你会看到,跑步速度这时就不再只是解释文字,而是真正进入概率公式。

不过题目没有给 L,也没有给 X 的分布。所以正式结论仍采用最小时间模型;积分版本只是告诉我们,如果要把问题做成更严肃的数学建模,它应该往哪里扩展。

赶上车的概率

先回到最小模型。列车停站 30 秒。只要乘客在这 30 秒内位于“能跑进车厢”的距离,就认为能赶上。

人的速度是 3 米/秒,所以如果列车刚开门时,人最多可以在:

3 米/秒 × 30 秒 = 90 米

也就是说,题目里的跑步速度给出了一个空间解释:开门那一刻,如果你离车门不超过大约 90 米,而且中间没有障碍、能直接跑到车内,那么理论上能赶上。

在最小模型里,我们把“是否处在可达距离内”折叠进题目条件,不再单独建距离分布。因此概率本身由时间窗口决定。一个发车周期是 600 秒,能赶上的窗口是 30 秒:

P(单次赶上) = 30 / 600 = 0.05 = 5%

10 分钟发车周期里的能赶上窗口。

这个 5% 其实挺直观:10 分钟里只有半分钟是“列车在站台且门还开着”的状态。你随机到达,刚好落进这半分钟,概率就是二十分之一。

如果用积分语言重写这个最小模型,它就是:

P(单次赶上) = (1 / 600) × ∫[0 到 30] 1 dt
            = 30 / 600
            = 5%

这里的被积函数是 1,意思是:在这 30 秒内,模型认为条件都满足;在窗口外,条件不满足。正因为被积函数是常数,最后才退化成简单除法。

如果连续 4 次都能赶上,并且把每次出行看成相互独立,那么:

P(连续 4 次赶上) = 0.05^4
              = 0.00000625
              = 0.000625%

换成更好理解的说法,大约是:

1 / 160000

也就是 16 万分之一。

这里的“连续 4 次都能赶上”不是说每天都准点赶上地铁,而是在这个简化模型里,每次都随机到达,结果每次都落在那 30 秒窗口里。这个概率已经很小了。

“非常倒霉”的概率

第二个问题更有意思。

题目定义的“非常倒霉”是:列车关门的那一刻,乘客正好位于距离列车 50 米以内,但没能赶上。

这个描述本来是空间条件。为了用题目给出的速度把它转成时间窗口,我们可以把 50 米折算成跑步时间:

50 米 / 3 米/秒 = 16.666... 秒

也就是说,关门那一刻如果你距离车门 50 米以内,你大概只差不到 16.67 秒的奔跑时间。按时间窗口理解,这相当于:你错过了关门,但错过得非常近,只差一个 16.67 秒以内的窗口。

所以“非常倒霉”的时间窗口是 16.67 秒。总周期仍然是 600 秒:

P(单次非常倒霉) = 16.666... / 600
              = 0.027777...
              = 2.78%

如果写成积分,也只是:

P(单次非常倒霉) = (1 / 600) × ∫[30 到 46.666...] 1 dt
              = 16.666... / 600
              = 2.78%

这说明它不是另一个神秘事件,只是关门之后紧挨着的一个窄时间窗口。

关门后 50 米对应的非常倒霉窗口。

这个概率比“赶上车”的 5% 小一些,但没有小到离谱。它大约是 36 分之一。

2.78% ≈ 1 / 36

所以,偶尔遇到一次“车门刚关,我人已经快到了”,不算玄学。它本来就可能发生。

真正离谱的是连续 4 次都这样。

P(连续 4 次非常倒霉) = (1/36)^4
                  = 1 / 1679616
                  ≈ 0.000000595
                  ≈ 0.0000595%

换句话说,大约是 168 万分之一。

如果一个人连续四个周六都在同一时间去坐车,每次都在关门时离车 50 米以内却没赶上,那就不只是“今天运气差”了。要么他的出门节奏稳定地卡在了一个很糟糕的位置,要么这个“随机到达”的假设已经不成立。

为什么连续事件要乘起来

很多概率题容易在“连续几次”这里出错。

如果每次事件相互独立,连续发生的概率就是逐次相乘。

单次赶上是 5%,连续 4 次就是:

5% × 5% × 5% × 5%

单次非常倒霉是 2.78%,连续 4 次就是:

2.78% × 2.78% × 2.78% × 2.78%

关键在“独立”两个字。

如果你每周六都是同一套动作:同一时间出门、同一路口等红灯、同一个安检口、同一个电梯、同一个步速,那这些事件未必独立。你可能不是随机落在 600 秒周期里,而是稳定地落在某个区间附近。

这时连续几次都赶上,或者连续几次都刚好错过,就不再只是概率问题,而是你的出行流程和地铁时刻之间发生了同步。

这也解释了一个生活现象:有些人总觉得自己“每次都差一点”。很多时候不是命运针对你,而是你的出门节奏刚好让你反复落在同一个糟糕窗口。

这题为什么不止是简单概率

如果只问“30 秒占 600 秒多少”,确实太简单。

但建模的重点不是把题做复杂,而是把边界说清楚。这个例子至少有三层模型。

第一层是时间窗口模型。它只看发车间隔和停车时间,得出 5% 和 2.78%。这是本文最终采用的答案,因为它严格依赖题目已给条件。

第二层是时间加距离模型。它把乘客与车门的距离 X 放进来,赶上车变成:

X <= v × 剩余开门时间

这一层会用到距离分布,也就会用到积分。

第三层是行为模型。现实里人不是随机均匀到站:有人看实时到站,有人固定时间出门,有人会在闸机、电梯、扶梯处被打断。连续四次都赶上或连续四次都倒霉,往往说明行为节奏和列车时刻发生了稳定关系,而不是每次独立随机。

所以这道题的计算不难,难的是别把模型讲错。简单模型可以给出明确答案,复杂模型能告诉我们还缺哪些数据。

用一段 Python 验证

这个最小模型也可以用很短的 Python 代码验证。

interval = 10 * 60
stop_time = 30
speed = 3
unlucky_distance = 50

catch_probability = stop_time / interval
four_catches = catch_probability ** 4

unlucky_window = unlucky_distance / speed
unlucky_probability = unlucky_window / interval
four_unlucky = unlucky_probability ** 4

print(catch_probability, four_catches)
print(unlucky_probability, four_unlucky)

输出对应:

0.05 0.00000625
0.027777777777777776 0.0000005954...

换成百分比:

事件小数百分比约等于
单次赶上0.055%1 / 20
连续 4 次赶上0.000006250.000625%1 / 160000
单次非常倒霉0.02777782.78%1 / 36
连续 4 次非常倒霉0.0000005950.0000595%1 / 1679616

这个结论怎么用

单次赶上车的概率是 5%,说明如果你完全随机到站,不能指望靠运气撞上刚开门的车。

单次非常倒霉的概率是 2.78%,说明“刚关门我就到了”并不罕见。一个人坐地铁次数多了,总会遇到几次。

连续 4 次都赶上,约 16 万分之一;连续 4 次都非常倒霉,约 168 万分之一。这样的连续事件如果真的发生,更可能说明你的出门节奏不是随机的,而是稳定地和列车时刻发生了某种对齐。

所以最实际的建议不是“祈祷运气变好”,而是把出门时间整体前移一两分钟。

对 10 分钟一班的地铁来说,提前 2 分钟不是小变化。它相当于把你从一个很窄的倒霉窗口里推出来,进入更宽的安全区。概率题算到最后,结论还是很朴素:别卡点。

微信公众号

欢迎关注「字与码」

如果这篇文章对你有用,也欢迎在微信里继续关注后续更新。

微信公众号字与码二维码