两个人约在 12:00 到 13:00 之间见面,先到的那个最多等 15 分钟,等不到就走人,问两人能碰上的概率——这道题我第一次撞见是在一次笔试里,当时整张卷子就它看着最“人畜无害”,结果我在草稿纸上画了半天时间轴,越画越乱。后来才反应过来,这根本不是一道“时间题”,而是一道几何概型题:把两个人的到达时刻当成平面上一个点的横纵坐标,相遇概率就等于正方形里某块区域的面积占比。算出来的结果是7/16,也就是 0.4375,不到一半。这个数字挺反直觉的——很多人第一反应是“等 15 分钟,总共 60 分钟,四分之一多一点吧”,也有人张口就是 0.25 或者 0.75,全都不对。这篇东西我打算把这道题从“看图猜答案”一路拆到“能写代码验证、能改参数、能套到真实场景里”的程度,顺带把几种常见的变体和我自己踩过的坑一起摆出来。不管你是正在准备笔试面试,还是单纯想搞清楚“等待 15 分钟到底值不值”,或者需要给团队讲一次概率入门,下面这些应该都够用。
1. 先把“约会”翻译成数学语言
1.1 为什么答案一定藏在“面积”里
这道题最容易走偏的地方,是一上来就去算“先到的人什么时候到、后到的人什么时候到”,按时间段分类讨论。我最初就是这么干的:假设甲 12:00 到,那他必等到 12:15;假设甲 12:10 到,那他要等到 12:25……分类分到第十种就发现,这不是在解题,是在给自己挖坑。正确的姿势是换个视角:不要分别看两个人,而是把两个人当成一个整体。设甲到达的时刻是 x,乙到达的时刻是 y,那么“这一次约会”的全部可能结果,就是有序数对 (x, y)。x 有 60 分钟的可能取值,y 也有 60 分钟的可能取值,把所有组合铺开,恰好就是一张 60×60 的正方形纸。每一次真实的约会,都是往这张纸上随机戳一个点。这么一想,问题立刻从“时间轴上的追赶”变成了“平面上的落点”,后面的所有计算都变成了数格子、算面积。
之所以能这么干,靠的是三个前提,缺一不可:两人的到达时刻都在区间内均匀分布、两人的到达互不影响(相互独立)、时间是连续的。题目里只说了“约好 12:00—13:00 之间见面”,没给更多信息,那么最自然、也是最中性的假设就是:这个小时里任何一个时刻到达的可能性一样大,而且甲几点到跟乙几点到毫无关系。这三个前提一旦成立,“概率 = 满足条件的面积 / 总面积”就是严格结论,而不是近似。很多人在这一步不自觉地加了额外假设,比如“约 12 点那大概率就是 12 点前后到”,那分布就不是均匀的了,答案也会跟着变——这个后面单独说。
1.2 把 12:00 记作 0,把 13:00 记作 60
单位换算这一步看着像废话,实际上能省掉后面一大半的符号错误。把 12:00 定为原点 0,把 13:00 定为 60,单位是分钟,于是 x、y 都落在闭区间 [0, 60] 上,正方形的边长是 60,总面积 3600(单位是“分钟×分钟”,虽然听起来别扭,但它就是面积)。你也可以把区间归一化成 [0, 1],让 x、y 表示“这一个小时里过了百分之几”,边长变成 1,总面积变成 1,最后的比值一模一样。我个人的习惯是用分钟算、用比例验:给出 7/16 这个答案之后,再用 0.25 这种无量纲的量去检查一遍,两边对得上才敢下笔。新手最常犯的错是把“15 分钟”和“60 分钟”混着往公式里塞,一会儿用小时一会儿用分钟,算出来的数看着挺像那么回事,其实早就错了。
还有个小细节值得提前说清楚:边界到底取不取等号。严格讲,先到的人“等不超过 15 分钟”,也就是两人到达时刻之差小于等于 15 分钟就算碰上了。在连续模型里,差值恰好等于 15 的概率是 0(一个点、一条线的面积都是 0),所以写成 ≤ 15 还是 < 15,结果完全一样。这不是糊弄,而是连续分布的性质。但如果你把时间离散成整分钟,这个区别就真实存在了,答案会变——这也是一个非常经典的坑,后面第 4 节会专门算给你看。
1.3 相遇条件其实就是一条绝对值不等式
现在把“先到的人等 15 分钟”翻译成式子。假设 x 是甲到达的时刻,y 是乙到达的时刻,那么两人的时间差是 |x − y|。这个绝对值表达的意思很朴素:不管谁先到,只要两个人的到达时刻相差不超过 15 分钟,晚到的那个人推门进来的时候,先到的人还没走。所以相遇的充要条件就是
|x − y| ≤ 15
注意这里不需要区分谁先谁后,绝对值天然把“甲先到”和“乙先到”两种情形合并处理了。很多人写条件的时候非要分情况,写成“x ≤ y 且 y − x ≤ 15”或者“y < x 且 x − y ≤ 15”两段,逻辑上没错,但画图的时候容易只画一半,最后算出来的面积漏掉一半,答案直接砍半变成 7/32。我在草稿纸上见过太多次这个错误,包括我自己第一次做的时候。记住一句话:绝对值就是对称性,对称性就是“另一半照抄”,画图时两块区域一定是对称的。
顺便把“为什么不能直接拿 15/60 出来”这件事说透。15/60 = 0.25,看着很诱人,但它算的是“乙的到达时刻落在甲到达后 15 分钟内”的概率,而这只覆盖了“甲先到”这一半情形,还没考虑甲等不到会走、乙先到时甲还没来等等。有人接着想“那不就两种情形,加起来 0.5 嘛”,答案是 0.4375,也不是 0.5。原因在于这两块“15 分钟宽”的带子在正方形里是斜着放的,它们有重叠、也有出界,不是简单相加。真正干净的算法只有一条:画图、算面积。
2. 7/16 是怎么一步步算出来的
2.1 正面算很烦,补集算两分钟搞定
在 60×60 的正方形里,|x − y| ≤ 15 描述的是沿着对角线的一条“斜带子”,带宽在坐标轴方向上正好是 15。这条带子的形状是个六边形,直接求面积需要把它切成几块,虽然能算,但容易出错。老手的做法是反过来算补集:先把“两人碰不上”的区域数清楚,再用总面积减掉。碰不上意味着什么?意味着其中一个人走了之后,另一个人才到,也就是 |x − y| > 15。
这块区域非常规整,是两个等腰直角三角形。先看 x − y > 15 那一块:在正方形里,x 最大 60、y 最小 0,这个区域贴着正方形的右下角,两条直角边分别落在 x = 60 和 y = 0 这两条边上,直角顶点在 (60, 0)。它的两条直角边长度都是 60 − 15 = 45 分钟。为什么是 45 而不是 15?因为 15 分钟是“容忍度”,它从对角线上被“吃掉”了一截,剩下的才是碰不上的部分。这个 45 是整道题最关键的中间量,写错它,答案就全错。所以这一块的面积是
(45 × 45) / 2 = 1012.5
另一块是 y − x > 15,关于对角线对称,贴着左上角,直角顶点在 (0, 60),面积同样 1012.5。两块加起来 2025,占正方形总面积 3600 的比例是 2025/3600 = 0.5625 = 9/16。于是相遇的概率就是
1 − 9/16 = 7/16 = 0.4375
这个数我建议你直接背下来,因为它是这道题的“标准指纹”。如果你算出 0.4375 以外的数,先别急着怀疑题目,八成是自己某个 45 写成了 15,或者面积除以 2 忘了。
2.2 把 15 分钟换成 t,得到能复用的通式
单记住 7/16 用处不大,真正值钱的是通式。设整个时间窗长度为 T(这里是 60 分钟),一方的等待时长为 t(这里 t ≤ T),同样的几何构造,两个失败三角形的直角边都是 T − t,于是
p = 1 − [(T − t)² / 2 + (T − t)² / 2] / T² = 1 − (T − t)² / T²
把 t/T 记作 a,这个式子还能写成更好记的形式:
p = 1 − (1 − a)² = 2a − a² = a(2 − a)
这个表达式有个很舒服的性质:当 t = 0(谁都不等,同时到达才算)时,p = 0;当 t = T(等到时间窗结束)时,p = 1;中间的曲线是一条开口向下的抛物线,前期涨得快,后期涨得慢。我一般会拿这两个端点去检验公式有没有写反——如果你写成了 p = (t/T)² 之类的,代 t = T 得到 1、代 t = 0 得到 0,也能过检,但在 t = T/2 时会给出 0.25 而不是正确的 0.75,一验就露馅。所以检验公式至少要代三个点。
2.3 参数代进去,顺便看看“多等 5 分钟”到底值不值
把 T = 60 固定下来,逐个代入不同的 t,能直观看到等待时长和成功率之间的兑换关系:
| 等待时长 t(分钟) | 相遇概率 p | 相比上一档的增量 |
|---|---|---|
| 5 | 0.1597 | — |
| 10 | 0.3056 | +14.6 个百分点 |
| 15 | 0.4375 | +13.2 个百分点 |
| 20 | 0.5556 | +11.8 个百分点 |
| 30 | 0.7500 | +19.4 个百分点(跨了两档) |
| 45 | 0.9375 | +18.8 个百分点(跨了三档) |
| 60 | 1.0000 | — |
这张表最值得看的是“增量”那一列:从 10 分钟加到 15 分钟,成功率涨 13.2 个百分点;从 15 加到 20,涨 11.8;越往后,每多等 5 分钟换来的收益越小。这就是抛物线前陡后缓的直观体现。如果你把等待时长当成一种成本,那这条曲线直接告诉了你边际收益在哪儿开始明显下降。反过来说,如果领导或者产品经理拍板说“我们要 90% 的把握”,你可以直接反解方程:由 1 − (1 − t/T)² = p 得
t = T × (1 − √(1 − p))
代 p = 0.9、T = 60,得到 t ≈ 41.0 分钟。也就是说,想要九成把握,得等 41 分钟,而不是 15 分钟。这个反解公式在实际工作中比正着算有用得多,因为它回答的是“要达成目标,代价得多大”。
3. 从手算到代码:两种独立验证方式
3.1 蒙特卡洛模拟,二十行代码搞定
纸面推导容易出错,写几行代码跑一遍是最踏实的复核方式。思路简单到不需要解释:反复模拟“甲乙各自随机挑一个 0 到 60 之间的时刻”,统计有多少次两人的差值不超过 15,最后算频率。
import numpy as np rng = np.random.default_rng(20240501) # 固定种子,保证结果可复现 N = 2_000_000 x = rng.uniform(0, 60, N) # 甲的到达时刻 y = rng.uniform(0, 60, N) # 乙的到达时刻 meet = np.abs(x - y) <= 15 # 布尔数组,True 表示碰上 p_hat = meet.mean() print(f"模拟概率 = {p_hat:.6f}") # 大约 0.4375 上下浮动 print(f"理论概率 = {7/16:.6f}")我本机跑出来是 0.437526 这种量级的数,跟 0.4375 贴得很近。注意这里刻意用了向量化写法,两百万次模拟在普通笔记本上不到一秒就跑完;如果你写成 Python 的 for 循环,同样的样本量要跑十几秒,纯粹是浪费生命。这个习惯在真正做业务模拟的时候更重要——模拟类代码十有八九要反复调参数重跑,慢一倍就是折磨自己一倍。
3.2 模拟结果该信到什么程度
模拟跑出 0.4375 附近的数,不代表“差不多就行”,得知道误差有多大,否则你根本判断不了“这次跑出 0.4321 是代码写错了还是正常波动”。二项分布的标准误公式是 √(p(1 − p)/N),代 p = 0.4375、N = 2×10⁶,算出来约等于 0.00035,也就是说大约 95% 的模拟结果会落在 0.4375 ± 0.0007 之间。我见过有人用一万次模拟跑出 0.44,就断定理论值错了——一万次的标准误是 0.005,0.44 完全在正常范围里。这个坑我在早期做 A/B 测试模拟的时候踩过,当时差点因为样本量太小把一个正确的模型推翻。
还有个更隐蔽的坑:别用固定步长的网格去“近似”模拟。有人图省事,让 x 和 y 只取 0、0.1、0.2……这种离散值,那其实已经不是在算连续模型了,而是一种加权过的离散化,结果会系统性地偏高或偏低,跟真实答案差个千分之几,你还以为是模拟误差。想验证连续模型,就用真正的伪随机数。
3.3 用解析法再交叉验证一遍
除了模拟,还可以直接让程序把面积算出来,跟手算结果对照。做法是把正方形切成很细的网格,逐格判断条件是否满足,最后统计格子占比:
import numpy as np n = 4000 grid = np.linspace(0, 60, n) X, Y = np.meshgrid(grid, grid) inside = np.abs(X - Y) <= 15 print(f"网格法面积占比 = {inside.mean():.6f}") # 收敛到 0.4375网格法的误差随 n 增大按 1/n 的速度下降,取 4000 已经能得到小数点后四五位的准确值。我更推荐这种“两条腿走路”的验证方式:一条是随机模拟,一条是网格积分,两者互相独立,如果它们同时指向 0.4375,那这个答案基本可以锁死了。顺带一提,反解等待时长的脚本也是三行:
import math T = 60 for p in (0.5, 0.6, 0.8, 0.9): t = T * (1 - math.sqrt(1 - p)) print(f"目标把握 {p:.0%} -> 需要等待 {t:.1f} 分钟")跑出来是 17.6、22.0、33.2、41.0 分钟。注意第一个数:想有五成把握,得等 17.6 分钟,比直觉里的“一半时间”少很多,但也比 15 分钟多。15 分钟只给你 43.75% 的把握,这个结论拿去跟人掰扯“到底该等多久”特别有说服力。
4. 变体、陷阱和那些一改就翻车的细节
4.1 两个人愿意等的时间不一样长
真实场景里,双方的耐心很少对称。假设甲愿意等 15 分钟,乙只愿意等 10 分钟,条件就变成 −10 ≤ x − y ≤ 15。这时候两个失败三角形一大一小:x − y > 15 的那块直角边是 60 − 15 = 45,面积 1012.5;y − x > 10 的那块直角边是 60 − 10 = 50,面积 1250。总面积还是 3600,于是
p = 1 − (1012.5 + 1250) / 3600 = 1 − 2262.5/3600 ≈ 0.3715
通式是 p = 1 − [(T − a)² + (T − b)²] / (2T²),其中 a、b 分别是两人的等待时长。代入 a = b = t,正好退化成 2.2 节那个式子,这个自检一定要做,它能在三十秒内告诉你公式有没有写错。0.3715 这个结果也挺有意思:一方把等待从 15 分钟砍到 10 分钟,整体成功率从 43.75% 掉到 37.15%,掉了 6.6 个百分点。所以“谁多等一会儿”这件事对结果的影响是不对称的,短的那一方才是瓶颈。
4.2 三个人约见面,概率掉得比想象中快
顺手把这个模型推广到三个人:三个人要“碰在一起”,严格说不是两两都能碰上,而是三个人的到达时刻落在同一个长度为 t 的窗口内(也就是最大时刻减最小时刻不超过 t)。这个概率有现成结论,对 n 个人、窗口 T、容忍 t 的情况,令 a = t/T:
P(range ≤ t) = n·a^(n−1) − (n−1)·a^n
代 n = 3、a = 15/60 = 0.25,得到 3×0.0625 − 2×0.015625 = 0.1875 − 0.03125 = 0.15625,也就是 5/32,约 15.6%。两个人还有 43.75%,三个人直接掉到 15.6%,这个落差非常说明问题:人越多,“大家都等一会儿”这种松散约定就越不靠谱。这也解释了一个日常现象——两个人约饭成功率尚可,五个人约饭永远在改时间。真要凑齐三个人,要么把时间窗收窄(比如明确“12:15 之前必须到”),要么把等待时长拉长,靠 15 分钟的宽容度是不够的。
4.3 把连续时间当成整分钟,答案会变
这是我觉得最容易骗过自己的一种错。有人会说:“哪有那么精确,人都是整分钟到的。”行,那就把模型改成离散的:到达时刻只能取 0、1、2……59 这 60 个整数值,各以 1/60 的概率出现。此时“碰上”的条件仍然是差值不超过 15,但计数方式变了。总组合数是 3600,碰不上的组合是差值大于等于 16 的那些,差值 d 从 16 到 59,每种差值对应 2×(60 − d) 个有序对,求和得 2×(1+2+…+44) = 2×990 = 1980。于是
p = 1 − 1980/3600 = 1620/3600 = 0.45
0.45 和 0.4375 差了 1.25 个百分点。这个差异不是计算错误,而是模型变了:把连续时间塞进 60 个格子里,相当于给了每个人一点“额外宽容”,碰上变得更容易了。这个例子我经常拿来讲一件事:离散化不是免费的,它会悄悄改变答案。做业务模拟的时候,如果你把用户行为、到达时间、响应延迟统统按分钟或按天取整,最后算出来的指标跟真实情况有系统性偏差,那不是 bug,是建模选择带来的固有误差。
4.4 高频错误清单
| 错误答案 | 出错原因 | 正确做法 |
|---|---|---|
| 0.25 | 直接拿 15/60,只算了单侧的一小段 | 要算整块带状区域占正方形的比例 |
| 0.5 | 认为“甲先到”和“乙先到”各占一半,直接相加 | 两块区域有重叠,不能简单相加 |
| 0.75 | 把失败区域当成了边长 15 的三角形 | 失败三角形的直角边是 60−15=45 |
| 0.9375 | 用了 1 − (15/60)² | 括号里应该是 1 − 15/60,即 45/60 |
| 0.4375 但过程写错 | 结果蒙对,推导里把面积除以 2 又乘 2 | 老老实实写清两块对称三角形 |
| 0.45 或 0.44 | 把连续时间离散成整分钟 | 连续模型就用连续分布 |
这张表建议存下来。我带新人的时候发现,绝大多数错误都落在这五六种里,而且几乎都能在图上找到对应的“画错的那一笔”。所以我的建议始终是:先画图,再写式子,最后代数字,顺序反了就容易在符号里迷失。
5. 这道题在真实世界里的影子
5.1 面试官到底想考什么
这道题在笔试面试里出现的频率相当高,但它考的不是“你会不会背 7/16”。面试官真正在观察三件事:你能不能把一个生活描述转化成数学结构(从“等 15 分钟”到“绝对值不等式”)、你会不会选择合适的工具(几何概型而不是分类讨论)、你有没有自检意识(算完会不会拿端点或者模拟验一遍)。我见过不少人上来就写积分,虽然也能做对,但过程绕得厉害,还容易在上下限上翻车;也有人直接说“这就是几何概型,画个正方形就完了”,然后一分钟出答案——后者的分数通常更高,因为他展示的是判断力,不是计算力。如果你被追问“如果等待时间变成 20 分钟呢”,通式在手就能秒答 0.5556;如果追问“如果是三个人呢”,能说出“掉到 15% 左右”就足够让面试官点头了。
5.2 排队、接人、配送时间窗,本质是同一个模型
把“两个人”换成“乘客和司机”“用户和客服”“买家和快递”,模型几乎不用改。乘客叫车,司机 5 分钟后到,乘客愿不愿意在路边等 5 分钟?这本质上是两个随机到达过程的“重叠”问题,答案就是 2a − a²。配送时间窗的设计更直接:平台承诺“上午 9 点到 11 点送达”,用户在家等,这相当于双方都在一个 120 分钟的窗口里随机出现,用户耐心如果只有 30 分钟,用公式一算,碰上概率是 1 − (90/120)² = 0.4375,跟这道题一模一样。反过来,如果用户耐心是 60 分钟,概率就升到 0.75。这就是为什么很多平台愿意把时间窗做宽——宽一倍,成功率涨得比想象中多。
服务窗口的排班也能借用这个思路。两个同事要协作处理一件事,一个人上午随时可能在,另一个人只有半小时空档,那他们能碰上的概率就可以用这个模型粗估。当然真实场景里分布往往不是均匀的,人的到达时间有明显的高峰和低谷,这时候均匀假设就不成立了,得换成经验分布或者直接用模拟。但即便分布不正,这个模型给出的“基准线”依然有价值——它告诉你,在完全随机的情况下概率是多少,实际值偏离基准线多少,就说明存在某种结构(比如大家都习惯踩点到)。
5.3 等待时长到底该怎么定
这道题最实用的产出,是那条“边际收益递减”的曲线。假设你的场景里,每多等 1 分钟的成本是固定的(时间、烦躁、机会成本),而收益是成功率提升,那么最优等待时长应该定在“边际收益 = 边际成本”的位置。从表 2.3 能看出,10 到 15 分钟这一段每 5 分钟换 13 个百分点,15 到 20 分钟换 11.8 个百分点,25 到 30 这一段只换大概 10 个百分点。如果你的成本很低(比如就是在咖啡馆坐着刷手机),多等一会儿划算;如果成本很高(比如在路边站着、在寒风里等),那就该把等待时长压到 10 分钟附近,接受一个 30% 左右的成功率,然后靠“提前确认”“实时共享位置”这类手段去改变模型本身,而不是硬扛时间。
我个人在实际协作里更倾向于另一个思路:与其延长等待,不如压缩不确定性。这道题里所有糟糕的结果都来自“两个人的到达时刻相互独立且分散”,只要让其中一方的时间变得可预测(比如“我 12:20 一定到,你按这个时间来”),方差就塌缩了,概率会迅速逼近 1。这比把 15 分钟改成 30 分钟有效得多,成本也更低。
6. 常见问题速查与几个我踩过的坑
6.1 速查表
| 问题 | 结论 | 备注 |
|---|---|---|
| 标准答案是多少 | 7/16 ≈ 0.4375 | 60 分钟窗口,双方各等 15 分钟 |
| 通式怎么写 | p = 1 − (1 − t/T)² | 等价于 2a − a²,a = t/T |
| 想达到五成把握要等多久 | 约 17.6 分钟 | 反解 t = T(1 − √(1−p)) |
| 想达到九成把握要等多久 | 约 41.0 分钟 | 同上 |
| 一方只等 10 分钟会怎样 | 概率降到约 0.3715 | 短的那一方是瓶颈 |
| 三个人呢 | 约 0.1563(5/32) | 指三人落在同一 15 分钟窗口内 |
| 按整分钟算呢 | 约 0.45 | 离散化会系统性抬高概率 |
| 两人恰好同时到的概率 | 0 | 连续模型下单点概率为零 |
6.2 几个真正会绊住人的细节
第一个坑是画图时只画一半。|x − y| ≤ 15 是横跨整个正方形的带状区域,很多人只画了右下角那一块,算完发现是 0.28 左右,然后怀疑人生。我的习惯是画完图之后数一数“失败区域”有几块——一定是两块,对称的,如果只数出一块,说明漏了。
第二个坑是把 45 和 15 搞混。失败三角形的直角边是 T − t = 45,不是 t = 15。这个错误出现频率极高,因为 15 这个数字在题面里太显眼了,脑子会自动抓它。我的应对办法是做个量纲检查:如果失败区域真的只有 15 分钟宽,那“碰不上”的概率会小得可怜,可现实明明有超过一半的概率碰不上,所以直角边必须是大数。这种“用常识反推数量级”的习惯,比任何公式检查都管用。
第三个坑是误以为“等 15 分钟”等于“覆盖 15/60 的时间”。带宽确实是 15 分钟,但它斜着穿过正方形,覆盖的面积比例是 1 − (45/60)² = 0.4375,不是 0.25。斜带的面积永远比“宽度 × 长度”的朴素直觉大一些,因为它是沿着对角线铺开的。
第四个坑是在模拟代码里把边界条件写反。写成np.abs(x - y) < 15和<= 15在连续模型里没区别,但如果你的数据是离散的(比如从整数里抽),这一符号之差会影响结果。写模拟代码时我一律用<=,并且顺手打印一下边界命中的次数,如果次数不为零,说明数据是离散的,得回头检查模型假设。
最后一个算是经验之谈:讲给别人听的时候,别一上来就写公式。我的固定讲法是先问一句“你觉得能碰上的概率有多大”,让对方猜一个数(十有八九会说 0.25 或者 0.5),然后画那个正方形,把两个三角形涂黑,说“这半边是碰不上的”,对方基本立刻就懂了。这个过程比推一遍积分有效得多,也顺带说明了为什么几何概型是个好东西——它把抽象的积分变成了可以看见的面积。至于这套东西还能往哪儿延,我最近在拿它算多人的会议到场概率,把“等待 15 分钟”换成“会议开始后 10 分钟内到场都算有效参与”,结论依然成立,只是 n 从 2 变成了 5,概率掉到了个位数,也算是给“开会永远凑不齐人”找到了一个数学解释。