
两个人约在 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相比上一档的增量50.1597—100.305614.6 个百分点150.437513.2 个百分点200.555611.8 个百分点300.750019.4 个百分点跨了两档450.937518.8 个百分点跨了三档601.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.0050.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.5y − 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/TP(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×(12…44) 2×990 1980。于是p 1 − 1980/3600 1620/3600 0.450.45 和 0.4375 差了 1.25 个百分点。这个差异不是计算错误而是模型变了把连续时间塞进 60 个格子里相当于给了每个人一点“额外宽容”碰上变得更容易了。这个例子我经常拿来讲一件事离散化不是免费的它会悄悄改变答案。做业务模拟的时候如果你把用户行为、到达时间、响应延迟统统按分钟或按天取整最后算出来的指标跟真实情况有系统性偏差那不是 bug是建模选择带来的固有误差。4.4 高频错误清单错误答案出错原因正确做法0.25直接拿 15/60只算了单侧的一小段要算整块带状区域占正方形的比例0.5认为“甲先到”和“乙先到”各占一半直接相加两块区域有重叠不能简单相加0.75把失败区域当成了边长 15 的三角形失败三角形的直角边是 60−15450.9375用了 1 − (15/60)²括号里应该是 1 − 15/60即 45/600.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.437560 分钟窗口双方各等 15 分钟通式怎么写p 1 − (1 − t/T)²等价于 2a − a²a t/T想达到五成把握要等多久约 17.6 分钟反解 t T(1 − √(1−p))想达到九成把握要等多久约 41.0 分钟同上一方只等 10 分钟会怎样概率降到约 0.3715短的那一方是瓶颈三个人呢约 0.15635/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概率掉到了个位数也算是给“开会永远凑不齐人”找到了一个数学解释。