1 - 从现实问题到数学模型

1 - 从现实问题到数学模型

Gavin0576 MSCS@Columbia

欢迎,进来坐。既然是第一篇,我们先不急着打开软件,也不拿一整页公式迎接你。建模最初的那一步其实很朴素:有人讲了一件现实中的事,我们能不能耐心听完,弄清他到底想知道什么?这个问题问明白了,后面的计算才有落脚的地方。

我们先从一个小谜题聊起。一个人平时下午 6:00 在车站等家人开车来接。有一天,他 5:30 就到了,没有打电话,而是沿着家人平常开来的路往回走。两人在半路碰上,回到家时竟比平时早了十分钟。他走了多久? 如果你第一反应是“题目没给车速,怎么算”,很正常,我第一次看到也会这样想。先把疑问留在心里:也许我们缺的不是一个速度,而是还没留意到哪一段路被省下了。

这篇博客里,我们还会遇到校园班车、野外样本箱、食堂排班、配送车和自习室,也会聊一个有点反直觉的滑雪场问题:为什么游客都希望缆车快一点,老板却可能希望它慢一点?故事看起来不相干,想问题的方式却很相似:先听懂对方的困扰,说明我们暂时相信什么,做一个自己也能检查的小计算,再想想什么现象会让我们改主意。这就是我想和你一起练的建模。它不是急着给数据贴一个算法的名字,而是为了回答眼前的问题,先画出一个足够简单、又没有丢掉关键过程的小世界。

模型基础

这五句话摆在一起有点像表格,但它们想避免的是一件很真实的遗憾:我们认真算了半天,回答的却不是别人关心的事。假如有人说“校园班车太差”,我想先请他多讲一点。是车上太挤,还是晚上等不到车?或许真正难受的是早上明明赶上了班车,却仍然迟到。假设管理者最后把问题说成:“8:30 多发一辆车,能不能在预算内让至少 90% 的乘客在 9:00 前走进教室?”到这里,我们终于知道要比较什么方案,也知道什么结果才算帮上忙。

问题清楚一些后,我们再沿着一个学生的早晨走一遍:到站、等车、上车、乘车、下车,最后走到教室。如果目标是“进教室”,那最后几分钟步行也算在内;只算车到终点,表就停早了。早餐和下课后的安排,这一次大概不必纳入。边界并不是把现实尽可能多地装进模型,而是诚实地说清楚:哪些过程和这次决定有关,哪些我们暂时放在一边。

不妨把时钟停在 8:35。现在要猜五分钟后会怎样,我们大概想知道每站等着多少人、车在哪里、空位还剩几个、路上堵不堵;我们不需要知道每个学生下午去做什么。这些能让我们接着往下推的“此刻情况”,就是状态。接下来,乘客到来、车靠站、座位被占满、车辆驶离,状态便一步步改变。第一次建模时,我们可以先把到站率和车程当作固定的;只是要记住,这不是在宣布它们永远不变。下雨天很可能是另一回事,那时要么修改模型,要么老实说明这次的结论只谈普通天气。

还有一个问题不能留到最后才想:怎么知道自己的建议有没有帮上忙?既然我们关心学生是否迟到,就应记录他们真正进教室的时间,而不只看车到站没有。预测和实际差在哪里,特别是那些依旧赶不上的早晨,都值得回头看看。这样一来,前面的目的、边界、状态和机制才有了接受检验的机会;它们不再只是几个漂亮的名词。

从乘客到站、排队、乘车到进入教室的校园班车系统边界
因为决策关心的是 9:00 前走进教室,所以边界结束在教室,而不是班车终点。图中的每个环节也对应一个可以记录或检验的量。

你看,我们甚至可以先不碰全校数据。设想 8:30 有十个人等车,8:35 到的车只剩八个座位,下一辆要再等十分钟。第一辆最多带走八人,这件事一眼就能核对。如果程序说十个人全上去了,我们大概不是缺一个更厉害的求解器,而是漏写了“座位只有八个”。把这样的小场景走通后,再逐渐加站点、随机到站和真实车程,心里会踏实得多。

班车的故事让我们把五个问题连了起来。不过,到目前为止我们只是用语言推演。换到下面这个保温箱,温度会随着每次放入样本而改变,“状态”为什么重要,就能在数字里看得更清楚。

边界与状态

想象一支野外采样队在整理当天收集的样本。瓶子还是室温,保温箱里却放着预冷的蓄冷体;每放进去一瓶,箱内就会暖一点。为了能把问题算下去,我们先约定一个演示用的上限:箱内物体不能高于 。在碰到这条线之前,最多能放进多少瓶? 你可能想直接数瓶子,但不妨先想想:第十瓶面对的箱子,已经不是第一瓶面对的那个温度了。我们用 记放进 瓶后的箱温,先假设蓄冷体与已放入的瓶子能达到同一个温度。

我想在这里把话说清楚:这个例子算的是理想化的箱内共同温度,不是在替真实样本制定保存规范。现实里,还要看每瓶样本自身的温度、暴露时间、摆放位置和污染风险。即使模型说箱温合格,也不能据此断言样本一定安全。我们暂时缩小问题,只是为了把能量怎样转移看明白。

温暖的新样本瓶进入装有蓄冷体和已有样本瓶的保温箱
一次装瓶步骤:新瓶带入的热量,会在我们选定的边界内重新分配给蓄冷体和所有已经放入的瓶子。

系统边界与能量平衡

我们只盯住“再放进一瓶”的短短一步。此时箱内有蓄冷体和先前放好的 个瓶子,外面还有一个温暖的新瓶子。用 表示蓄冷体的有效热容, 表示每个相同瓶子的有效热容,单位都是焦耳每摄氏度;新瓶入箱时的温度叫 。如果这一小步里外界几乎没有热量进入,而箱内物体又很快达到共同的 ,新瓶放出的热就应该等于箱内原有物体吸收的热:

整理得到状态更新式

看到式子里多出来的 ,也许你会问:为什么前面放过的瓶子还要算?因为它们没有被取出,下一瓶带来的热也会分给它们。这个细节一旦漏掉,后面算出的瓶数就会偏小。顺手再检查两个直觉:等式两边的单位都是焦耳;新温度既然是混合后的结果,就该落在原箱温 与新瓶温 之间。单位或范围不对时,先回头看式子,往往比继续代数字更有用。

状态演化与温度阈值

给这个假想保温箱一组数:、、、。它们只是演示用的设定,不是实测参数。第一瓶放进去后,温度变成

第一瓶只让温度升高约 。这个变化不大,和“小瓶子的热容远小于蓄冷体”的设定相符。但第二瓶不会简单地再加同样多:箱子已经暖了一点,第一瓶也还留在里面。若把最初的蓄冷体和后来 个瓶子带入的能量放在一起算,会得到

分子是初始蓄冷体与所有新瓶带入的能量,分母是它们合起来的热容。要求 ,代入数字就是

分母一直是正的,整理后得到 ,也就是 。瓶子不能只放 0.11 个,所以在这套设定里,最多是 116 瓶:第 116 瓶后约为 ,第 117 瓶后约为 。这个临界点很清楚,但它只属于我们刚才画出的那个理想箱子。若真要装样本,还得让测量和保存规范来决定能否采用它。

你可能会想:既然目标温度已经定在 ,能不能直接做一次总能量平衡?可以。蓄冷体从 4 度升到 8 度,吸收 焦耳;每瓶从 20 度降到 8 度,放出 焦耳。两者相等,就得到同一个瓶数上限。不过,这并不表示“每次放瓶,传入箱内的热量都一样”:装箱过程中的即时温差一直在变。逐步更新的公式仍然有用,尤其当你要检查中途温度、不同瓶子或开盖漏热时。

系统边界的实证检验

现在想象你真的把“116”写进工作安排。写之前,我会想再去箱子旁边看看:蓄冷体到底有多大热容?每瓶进箱时是多少度?开盖要多久?箱顶和箱底的温度一样吗?如果上下温差很大,一个“箱温”已经说不清现场;如果一瓶都不放,箱子也慢慢变暖,外界进热就不能忽略。我们可以先把箱盖关好,观察与放十瓶相同的一段时间,再和实际装瓶时的升温比较。

记录时,至少写下第几瓶、放入时间、放入前后的温度、瓶子类型和开盖多久。哪怕先认真记录十次,也能看出第一瓶的升温是否接近 。如果实测升温大得多,我们再逐项找原因:瓶子的热容估小了吗?开盖时带进了热空气吗?温度计放的位置合适吗?蓄冷体有多少真正参与换热?瓶子不同,就让第 瓶使用自己的 ;外界也在加热,就在能量平衡里补上一个以焦耳计的热量项。每加一层,都要能指出它对应的现实过程。

假如现场放到 70~90 瓶就越过温度线,模型报出的 116 便值得重新审视。也许开盖带进了热,也许蓄冷体真正参与换热的部分比我们想的少;多报几位小数并不能弥补这些缺口。反过来,若保存规范本来只允许放 40 瓶,把热学估计从 116 修正为 110,眼前的决定也不会变。我们不需要把每一处细节都算到极致,只要先认真弄清哪些细节真的会改变选择。比如蓄冷体的热容减半时,在其余条件不变的模型里,未经取整的可装瓶数也会减半;这是一个很好用的方向检查。

保温箱这段看的是热量如何在箱内分配。接下来我们换一个没有温度计的场景:食堂经理要安排员工。我们仍然先问同一个朴素的问题——她说出的每句话,在模型里究竟对应什么?

语言到结构

这当然不是让我们看见一个名词就添一个字母。它更像是在聊天时停下来确认:“这些信息是已经知道的,还是还要去量?我们究竟能改变什么?改到什么程度才算有用?”这几个问题若还含糊,先把话说清楚,比急着写目标函数更省时间。

假如食堂经理坐下来问:“中午有付款、备餐、取餐三个工位,都得有人;我手里只有四名员工。第四个人放在哪儿,大家能少等一些?”我们可以先在纸上画四个小圆点代表员工,三个方框代表工位。谁能做哪个岗位,就在两者之间连线。现在才给连线一个名字: 表示员工 被安排到工位 ,没安排就记作 0。这半小时里,每人只负责一个完整岗位,所以 ;每个工位至少有人,则是 。这些式子还没告诉我们哪种安排最好,只是先保证建议真能执行。

要回答经理,下一句自然是:“每个工位半小时究竟能处理多少人?”假设付款一人处理 25 人、两人处理 50 人;备餐一人处理 40 人、两人处理 70 人;取餐一人可以处理 80 人。预计有 60 人来。若第四个人去付款,三个工位的能力是 ,大家还是会在备餐前等;若他去备餐,就变成 ,队伍又会堵在付款处。再加第五个人、让付款和备餐各有两人,付款仍只有 50 的能力。算到这里,也许会有点沮丧:四人怎么安排都不够,五人也没把瓶颈消掉。但这恰恰是诚实的发现。经理可以考虑改流程、提高某个工位的处理能力,也可以把目标暂定为“让等待尽量少”,而不是假装眼下能让 60 人完全不排队。

顾客依次通过付款、备餐与取餐工位的食堂流程
顾客经过的是一条相连的服务链。提高一个工位的能力,只会一直有效到另一个工位成为新的最小容量环节。

如果这时把纸分成两栏,一栏写经理说过的话,一栏写模型里的对应项,遗漏会更容易看见。“每个人都能做所有岗位吗?”要落实为哪些连线存在;“取餐一直要有人吗?”要落实为岗位约束;“换人后能少等多久?”则需要服务时间和排队数据。假如一句重要的话找不到落脚点,我们可能漏了规则;反过来,若某个变量说不出从何而来,也值得问问自己是不是把精力放错了地方。

题目若还有好几个小问,可以再画几支箭头:到客预测交给排班,排班带来人工成本,最后才形成建议。箭头上写清传过去的是什么,队友接手时就不必猜。尤其要留意时间:如果 12:30 就得定排班,模型便不能偷偷用上 12:30 以后才会知道的到客情况。这样的预测即使漂亮,也帮不了当时的经理。说到这里,现实的话已经慢慢变成了数学结构;但那些“半小时能处理多少人”的数字,我们还只是暂时相信。接下来要谈的,就是怎样对待这种暂时的相信。

假设

比如我说:“这段路短,平时也不太堵,先近似认为车速不变;这样车程就和距离成正比。”你马上知道我为什么敢这么做,也知道它会怎样影响计算。如果只在报告开头列一句“假设速度恒定”,却不解释为什么,读者当然会问:下雨天或放学高峰也能这么算吗?假设不是一句求读者通融的话,而是我们主动交代的取舍。

保温箱刚好给我们一个可以检验的假设:箱内只有一个共同温度。我们不必凭感觉争论,在箱盖附近和箱底各放一支温度计就好。如果每次装瓶后两边读数接近,一个温度或许够用;如果一边是 ,另一边仍是 ,这一个数显然遮住了重要差异。等看见这种差异,再把箱子分成两个温区,有理由,也更容易知道新模型在解决什么问题。

“所有瓶子的热容都是 ,入箱温度都是 ”同样只是暂时的方便。小塑料瓶和装满液体的金属容器当然不同。可以记录类型、内容物、入箱温度,并让第 瓶使用对应的 。知道放入顺序,就按实际顺序更新;不知道,就试几个合理顺序,或根据观察到的比例做情景。还担心开盖进热?量开盖时长和估计热流功率。功率的单位是瓦,也就是焦耳每秒;功率乘时间,才是能与瓶子换热量放在同一方程里的能量。

我会把这些暂时的相信记在一张小表里:“箱温均匀”“瓶子热容相同”“开盖进热可以忽略”。每一行后面,再写为什么这样想、哪项结论靠着它,以及怎样观察才能发现它不成立。这样做不是为了让表格看起来专业。如果只需要装 20 瓶,哪怕真实上限比 116 低不少,安排可能仍很稳;如果计划装 115 瓶,少许漏热就值得认真对待。我们关心的是哪条假设会改变决定,而不是给每个参数都配一张好看的图。

承认假设,并不等于被现实的复杂吓住。我们可以先让一个小模型站起来,看看它在哪儿与观察不合,再补上缺的那一部分。这个过程通常比一开始就把所有可能的细节都装进去,更让人知道自己在做什么。

基线与扩展

如果简单的线性模型已经能稳稳地支持眼前的决定,我们不必因为深度网络听起来更厉害,就急着换掉它。当然,复杂方法有时非常值得用;只是希望它能换来某种说得清的好处,例如预测更准、关键机制更贴近现场,或者最终建议真的更好。

保温箱的第一层,就是刚才那个“温度均匀、没有外界进热”的递推式。下一层不必直接上机器学习,先做个实验:十分钟不放瓶,箱子自己会暖多少?若关着箱盖从 升到 ,快速装箱时这部分影响也许很小;若升到 ,就不能再装作它不存在。数据指出了漏洞,我们才给方程补上这股热量。

食堂也一样。先比较每半小时来多少人、能服务多少人。如果经理要知道的是“90% 的人会等多久”,只看总量就不够了:客人可能一阵一阵地来,服务时间也有长有短。我们可以让模拟器按时间记录事件:顾客来了,有空闲员工就开始服务,没有就排队;员工做完一单,再接下一位。这样得到的等待时间,再和真实午餐记录对照。如果高峰期的排班建议因此改变,复杂的一层就有了用处;若在需要决策的范围内,两种模型总给出同样的建议,简单的那一个也许已经够了。

下面这个例子,刚好能把前面讲过的目的、边界、状态、机制、假设和分层都串起来。它从一句听着不太对劲的话开始:“滑雪场的缆车,对老板来说可能越慢越好。”我们先不急着反驳它,而是问问它在什么目标下会成立,又在什么地方会失效。

滑雪场循环系统中的容量配置

站在滑雪者的位置,答案几乎不用想:缆车越快越好,队越短越好,一天最好能多滑几趟。这是很合理的游客目标。但老板可能问的是另一句话:“在雪道上同时滑行的人不超过舒适上限时,我最多能放多少位游客进来?”在这个很窄的目标里,游客坐在缆车上或排在围栏里的时间越长,他待在雪道上的比例就越小。他仍然是一位买了票的游客,却暂时不占用雪道。

所以,这个例子首先把我们拉回建模契约的第一句:你到底在为谁优化什么?“把缆车变好”不是目标。缩短平均等待、让每位游客多滑几趟、提高当日利润、限制雪道密度、增加入园人数,是五个不同的目标,它们甚至会给出相反的建议。

而且,日常语言里都叫“容量”的东西,至少要拆成三个量:

  • 雪道容量:某个时刻,坡面上能够安全、舒适地容纳多少人;
  • 缆车运力:一小时能向山上运送多少人次;
  • 雪场总人数:已经入园的所有人,包括正在下滑、排队、乘车、休息和吃饭的人。

如果把这三个概念混在一起,“慢缆车可以提高容量”当然像一句胡话。一旦把它们拆开,我们就能看见背后其实是一个“人在系统里怎样流动”的问题。

包含雪道、缆车、基地排队区和休息区域的滑雪场循环示意图
雪场不是一条孤立的雪道,而是一个循环系统。游客在雪道状态与缆车、队列、连接区和休息区等非雪道状态之间不断移动。

单循环流动模型

我们先画最小的边界:一部缆车服务一组雪道,雪场里有 位游客重复做着同一件事——上山、滑下来,再去上山。记 为一次真正待在雪道上的平均下滑时间, 为两次下滑之间的平均非雪道时间,它包括排队、乘缆车上山、上下车和走过连接区。一整圈需要

先做几个很清楚的假设:我们只看一段大致稳定的时间,游客不断重复这个循环,大家的平均用时可以用同一组数来表示。一位游客在雪道上的时间比例,就是 。因此,某个普通时刻正在雪道上的预期人数可以写成

假如雪道上同时容纳 人时还算舒适,要求 ,便得到

所以,雪场总人数相对于雪道同时容量的倍数,可以写成

这就是老板那句话背后的第一层道理。下滑时间 不变,排队和上山时间 越长,每位游客一天里真正占用雪道的比例就越小。因此,在不超过雪道人数上限的情况下,系统里可以留着更多买了票的人。

但一定要看清这个式子没说什么。它没说雪山变大了,没说缆车运力提高了,更没说游客滑得更开心。它只是说:在我们画出的边界里,可以把更多人留在排队区、缆车上和基地,同时让雪道上的人数不变。

容量的数值比较

假设雪道上同时有 人时还算舒适,滑完一趟平均需要 分钟。在缆车比较快的情形下,排队、上山、上下车合计 分钟,那么

这表示,雪场里有 1,000 位游客时,在这个平均模型里,大约 400 人在雪道上,其余 600 人在其他地方。现在假设服务变慢,队也更长,使 增加到 36 分钟,则

如果老板只看卖出去多少张票,这个慢一些的系统看起来可以多放 600 人进来,而雪道上的平均人数没有增加。若每张票卖 元,客源永远充足,排队又不影响投诉、退票和下次是否再来,收入 当然希望 越大越好。在这个特定模型里,“缆车越慢,老板越喜欢”是可以推出来的,不是一句玩笑。

快循环与慢循环下雪道人数和非雪道人数的堆叠比较
两个情景都把演示用的雪道人数保持在 400。慢循环下更高的总人数,完全来自更多游客被留在雪道之外;它并不意味着服务更好。

不过,请先别把 1,600 人写成经营建议。刚才的算法其实把长队当成了一个“存人的仓库”。它假设游客不会离开、不会投诉、不会要求退票,也不会因为今天只滑了几趟,明年就换一家雪场。它还只看全山平均人数;两条窄雪道的交叉口已经很危险时,全山平均数仍然可能很好看。这些都不是可有可无的细节,它们足以把结论翻过来。

“缆车变慢”本身也需要继续拆。如果吊椅之间相距 米,每把坐 人,缆索速度是 米/分钟,一个理想化的小时运力与下式成正比:

降低缆索速度,不仅会让乘车时间变长,也会让每小时通过登车点的吊椅减少。新建一部缆车则会增加总运力,同时改变哪些雪道被输送更多游客。所以 不是一个老板可以随意拧动的旋钮;它是缆车速度、数量、停车故障、游客数量和排队共同产生的结果。当来的人比能运走的人还多,队伍会一直增长,不会自动停在刚才那个整齐的平均值上。

多目标运营决策模型

第一层模型已经完成了它的任务:它解释了那个反直觉结论从哪里来。下一层不应该只是多加几个字母,而应该补上最可能改变决定的那部分:老板不仅赚今天的门票钱,还要支付设备成本,也离不开安全、口碑和明年再来的客人。

记 为缆车速度, 为运行中的缆车数, 为入园人数, 为预期等待时间, 为预期雪道人数。一个比较诚实的示意模型可以写成

同时要满足

表示设备与运行成本, 概括退票、客源流失、基地拥挤或服务失败带来的代价; 和 用来衡量老板对这些后果有多在意。速度的上下限也不是为了让式子显得完整:设备、风速、上车安全与疏散规则都会限定真正可用的速度。初级、中级和高级雪道还可以分开设密度约束,因为全山一个平均数很容易遮住真正危险的位置。

这个新模型并不会自动告诉我们“越快越好”。多修一部缆车可能很贵,也可能把游客太快送进本就拥挤的雪道。它同样不会告诉我们“越慢越好”:排队时间一旦损害口碑和未来收入,故意制造长队的损失可能比多卖几张票还大。真正的合理速度很可能在两个极端之间。建模最有价值的结果,不是一句“快”或“慢”,而是能讲清哪个权衡把我们推向了某个速度。

实证验证方案

缆车问题很适合做一张假设登记表。闸机时间戳可以估计运力和循环时间;定时人工计数或保护隐私的摄像头计数可以估计 ;售票与入场记录告诉我们现在有多少人;队列传感器、问卷、投诉、退票和复购情况则能检验等待是否真的不影响需求。这些数据还要按天气、工作日与周末、水平以及开放雪道分组。下了新雪、只开半座山的早晨,不是普通周二的那个系统。

在写复杂模拟之前,先找一个平稳时段检查小模型。如果雪场里 、、,现场是否真的大约有 400 人在雪道上?如果相差很大,也许游客会去餐厅休息,也许不同水平的下滑时间差得很多,也许我们的边界漏了另一部缆车。偏差不是丢脸的失败,它在告诉我们下一层该补什么。如果这些差异真的会改变经营决定,我们再把缆车队列当成节点、雪道当成有向连线,做一个随时间变化的网络模型。

现在,最开头的话可以被写得很准确:若老板只想在限制平均雪道人数的同时,让入园持票人数尽可能多,那么慢缆车确实可以让雪场总人数成为雪道容量的更大倍数。但若他在意的是几年的利润、安全、体验和复购,“越慢越好”就不再是必然结论。这个例子最有意思的地方,正是两句话都能在不同的建模契约里被推导出来。

保温箱的递推式、食堂的供需平衡和滑雪场的循环模型,都在声明好的假设下给出了答案。但任何一个都不能只凭纸上的漂亮结果,就保证现场会照着它走。接下来,我们把“检查”拆成几层,沿着从故事到代码再到建议的路慢慢走回去。

验证

五层检查问的并不是同一件事。代码照着方程运行了,方程仍可能没有抓住现实;过去几天预测得不错,明天一场雨也可能让建议失效。我们要做的,是让读者能从最后的建议一步步走回去,看见它从什么问题出发,经过哪些简化,凭什么相信结果。竞赛里提交的是这样一份能让人理解、核对的论证,而不只是一个会运行的程序(MCM/ICM 官方说明 )。

还是回到班车。第一层很好懂:程序有没有做我们交代它做的事? 站上十个人、车里八个空位,程序应该留下两个人。若它让十个人全上了车,我们就知道要先修实现。修好了也先别庆祝得太早:这只说明程序忠实执行了规则,还没说明规则本身描绘了真实的班车。

第二层,查结果本身有没有违反常识与约束。八个座位坐不下九个人;进教室不可能发生在上车之前;如果没有人自行离开队伍,下一分钟的等车人数应等于原来的人数加新来的人数,再减去上车的人数。容量、守恒和时间顺序,常常在还没收集大量数据时就能抓出错误。

第三层,拿没用来调模型的早晨做检验。记录实际到站、上车、行车、进教室的时间,用一部分日子估计参数,另一部分日子检验。若只在同一批早晨里又拟合又打分,模型可能只是记住了那几天。还有一种更隐蔽的作弊:8:30 要预测是否迟到,却把当天后来实际花了多少车程当成输入。每次都问自己:作决定的那个时刻,这项数据真的已经知道了吗?

第四层,是给旧方案一个公平的比较机会。假设原班次的准时比例是 78%,新方案预测达到 92%。这听着很鼓舞人,但我们得确认两边面对的是同样的到站情景、预算,以及同一个“准时”定义。新方案若超了预算,便不能直接推荐;旧方案测在雨天、新方案测在晴天,也没法凭两个百分比宣布胜负。简单的基线同样值得被认真对待。

第五层,看看建议有多稳。若车程比上周慢五分钟,新方案还够得到 90% 吗?若最忙的车站多来 20% 的人,谁会迟到?改动输入,重新计算,再找出哪个环节先失守。如果很小且合理的波动就能推翻建议,我们要说明它的适用条件,甚至预备加车、提前发车或换线路的方案。

假如现在要把结果交给调度员,我希望他看到的不只是“92%”。他真正需要知道的是:要改哪一班车,预计会好多少,遇到什么情况又可能不灵。我们可以这样写:“若预算允许,给 8:35 到站的班次增加一辆八座车;在演示数据中,预测准时率从 78% 升到 92%,但车程比平时慢五分钟以上时会跌破 90%。”这些数字只是为了示范怎样交代结论,不是哥伦比亚班车的实测数据。

也许你会觉得:这样讲下去,每个答案都带着条件,还能不能下结论?我觉得当然能,只是我们要说清结论是哪一种。通勤谜题在往返车速相同的条件下,给出确定的 25 分钟;两日行程靠连续性保证“存在”,却不告诉我们地点;保温箱的瓶数取决于参数和上限;缆车倍数是在一个故意缩小的循环模型里成立的数量关系,不是“让游客多排队就一定更赚钱”的经营证明;班车方案在普通日子可能经得起检验,大雨天却未必。把这些差别讲清楚,不会削弱答案,反而让人知道该在什么地方相信它。

计算前检查清单

遇到一个新问题时,我会先给自己半分钟,把几句最基本的话说出来:要选择什么或预测什么?哪些数是量到的,哪些只是先假定的?能不能做个小到手算得出的版本?它最可能在哪儿失效?以后拿什么证据检验?有一两句暂时说不清也没关系,那正好告诉我们下一步该问谁、查什么。带着这些问题,我们回到食堂,把从请求到建议的过程完整走一遍。

食堂案例

假设学校找到我们,说:“食堂排队能不能短一点?每周人工预算最好不要增加。”这句话听起来已经是一个任务了,真要动手时却还差几块拼图。谁能改排班?哪些岗位可以调?“短一点”是希望平均等待减少,还是最忙时不再排那么长?我们多问几句,不是在为难提问的人,而是在确保最后给他的建议真的能用。

第一步:定义决策陈述

我们试着把决定说成一句经理听得懂、也能点头或摇头的话:“根据预计到客量、各工位的服务速度、员工与工资,每半小时决定谁在哪个工位,尽量缩短等待,同时不违反预算和排班规则。”如果经理说:“其实我最担心的是有人排过十分钟”,那很好,我们现在就能调整目标,而不用等论文写完才知道自己听岔了。

现在再给量起名字。 是时间段集合, 是工位集合; 是时段 到达工位 的预计顾客率, 是工位 每名员工的服务率, 是那段时间分配到该工位的员工数。这里最重要的区别不是符号长什么样,而是谁能改变它:经理能决定 ,却不能命令顾客少来。 和 得从数据估计。若把到客量也丢给优化器“自由选择”,它自然会给出一个没人来吃饭的完美食堂——却毫无用处。

第二步:确定系统边界

我们可以先把顾客到达、点餐、付款、备餐和取餐圈进来,拿到餐后去哪里则暂时不管。但要看看取餐口:如果它一堵,备好的餐没地方放,备餐也跟着慢下来,那它就在系统里;如果不会影响上游,第一版可以略去。边界没有标准答案,关键是别把决定排队长短的环节划到外面。

顺手在每个量旁边写单位。 是顾客/分钟, 是顾客/(员工·分钟),所以 是顾客/分钟。于是可以先估一个利用率

它没有单位,就是“来的人有多快”除以“能服务得有多快”。若 ,平均到客速度已经追上或超过服务速度;在这种近似下,队伍很难稳定地消下去。我们还没用复杂排队论,却已经有了一道很有用的第一关。

第三步:区分观测与假设

收银记录里的到客时间、每单耗时和实际排班,是我们观察到的;“各单服务时间互不影响”“一名员工这半小时的服务速度不变”,才是模型加上的假设。尤其别只看一个平均数:同样是平均两分钟,可能每单差不多两分钟,也可能大多数半分钟、少数十分钟。两种午餐高峰的队伍会很不一样。

刚才的假设记录表这时就派上用场了。以“服务率在半小时内不变”为例:理由也许是这段时间工作方式相同;好处是容量容易算;检验方法是看午餐开始的五分钟是否总比后面慢。说不出数学后果的假设太空,说不出怎样检查的假设则暂时只是猜测。

第四步:构建基线与一项扩展

第一版可以很朴素:安排足够多的人,让估计的利用率低于一个预先选定的线,比如 。它没有描述顾客扎堆到来的波动,但一眼能查。若经理特别关心“最慢的那 10% 顾客要等多久”,我们再用排队近似,或按每位顾客到来和离开的事件做模拟。用同一批到客情景比较新旧模型:建议若相同,第一版也许够用;只有尖锐的午餐高峰让建议变了,我们就知道该在哪一层加入波动。

第五步:定义证伪标准

先留几天数据,专门用来验模型。不要拿全部日子把参数调到最好,再拿同一批日子宣布自己预测得准。我们可以比较预测与实际的队伍长度、平均等待、90% 分位的等待时间,以及有多少时段超过服务目标;还要按星期几、每天的时间段拆开看。若中午准、快关门时不准,结论就该写“适用于午间”,而不是“适用于所有时候”。

这些符号暂时放在一边,我们陪经理看一个半小时。预计 12:00 到 12:30 会有 60 人来到付款台,一名员工半小时大约能服务 25 人。先猜猜:安排两人还是三人?两人的总能力约 50 人,因此只要 60 人都来了、也没人放弃,至少会有十人到半小时结束仍未被服务。三人约能处理 75 人,从总量看有余地;但如果顾客同时涌来,仍可能等上一阵。这个小计算没有给出完整排班,却已经帮我们排除了一个明显紧张的安排。

改成每分钟来看:到客率 人/分钟,单人服务率 人/分钟。两人时 ,三人时 。前者意味着如果这种速度持续下去,队伍会越积越长;后者说明平均能力留有余量,但客人若集中在某五分钟出现,照样会排队。

算到这儿,你也许会问:我们要不要马上学一套排队论?先看经理接下来想知道什么。如果只是问“第三个人值不值得考虑”,半小时的收支已经很有帮助;如果他问“90% 的人能不能在五分钟内轮到”,我们就得认真看顾客的到来时间和每单耗时。数学工具可以慢慢加,等它真正能回答一个前面答不了的问题时再请它上场。

也别只盯付款台。付款加了一个人,备餐可能就少了一个人,队伍只是换了个地方。假如额外找人每小时要 18 美元,半小时就是 9 美元;这笔钱是否值得花,要结合预算和等候时间的价值判断。若既没给等待上限,也没说明等待一分钟值多少钱,“最优排班”到底对什么最优,仍没有定义完整。

再故意把到客过程变得极端一点:60 人中有 30 人在前五分钟涌来。三名员工虽然半小时能服务 75 人,但头五分钟只能服务约 人,眼前还是会积下十七八个人。半小时总量把这个高峰抹平了。我们不必争论“真实情况也许如此”,直接查时间戳就能检验。若有记录,可以画累计到客量与累计服务能力,两条线拉开的距离大致对应队伍;再画预测等待与实际等待,看看误差是否总出现在午餐高峰。图应该帮助我们发现机制,而不只是装点页面。

最后把几种量再分清一次。60 位顾客会来,是观测或预测,不是经理能改写的决定;安排几名员工,才是她能选择的;半小时 9 美元是由工资算出的成本;“付款台最多三人”是硬约束;12:05 还有 18 人在等,是系统当时的状态。若到客数变成 75,三人利用率就到 1;若在 60 人时派四人,利用率降到 ,成本却更高;若收银变慢、每人只能服务 15 人,三人也只处理 45 人。这些变化各有不同的现实原因,别都含糊地叫作“调了一下参数”。

如果现在要和一位没看过公式的朋友聊食堂,我会这样说:“两个人赶不上来客的速度,队伍会积起来;加第三个人,平均能力够了,可大家若一起到,还是会等。真要改班次,还得看看其他工位和预算。”能用平常的话把这层意思讲明白,公式才算帮到了我们——它把决定照亮了,而不是把决定藏进符号里。

食堂这个例子把一整轮建模走完了。接下来不重新开三套流程,我们只换三副眼镜:有时找一个不变量,就不用知道所有速度;有时靠连续性,就能证明某件事必然发生;有时把过程拆成几个阈值,才能做出安全的选择。

计算前的分析

不变量分析:提前到达的通勤者

还记得开头那个提前到站的人吗?他 5:30 开始往家走,家人照平时的时间开车来,半路遇见他,结果早十分钟到家。你当时猜的是不是 30 分钟?这个答案很诱人,可他是在路上被接到的,不会一直走到 6:00。

我们不知道车速、步速和家离车站多远,先不要为缺数据发愁。只要车在往返这段路上速度一样,就盯住相遇点到车站这一小段:平常开车的人先向车站经过它一次,接到人后又往家经过它一次;今天两次都不用走。来回合计省了十分钟,单程自然是五分钟。所以车与人相遇的时刻,比平常到站时间早五分钟,也就是 5:55。人从 5:30 走到 5:55,走了25 分钟。

相遇后省去两段相同车程的通勤路线示意图
总共提前十分钟,是因为“相遇点到车站”这段路在去程与回程各省一次;两段相同,因此每段对应五分钟。

现在反过来挑毛病:如果回程开得更快,或者去回走的不是同一条路,两段车程就未必各省五分钟;如果家人接到电话提前出门,拿“平常 6:00 到站”作参照也不成立。我们用到的不变量,正是在未知速度和距离之外仍保持不变的往返对称。你当然可以把双方的位置都写成时间函数,再引入速度和距离联立求解;但看出那段路被省了两次,既省力,也把答案成立的理由亮了出来。

连续性论证:两天的行程

再换个场景。星期一早上 9:00,有人从村庄 出发,沿一条路走向 ,下午 5:00 前走到;星期二同样在 9:00,他从 沿原路回 ,也在 5:00 前走完。假设提前走到终点后,他会在那里待到 5:00。他会不会在两天的同一个钟点,站在路上的同一个地方? 两天走得快慢不必一样,中途停一停甚至折返也没关系。

不妨让“星期一的他”和“星期二的他”同时出现在眼前。早上 9:00,两人各在路的一端;下午 5:00,他们的位置正好对调。只要沿的是同一条连续的路,途中又不能瞬移,两人交换前后顺序就必定会碰面。那个碰面的地点,就是现实中他两天在同一钟点经过的地点。我们证明了一定存在,但还不知道它具体在哪里。

如果想写成数学语言,就用 表示从 沿路走出的距离,令 。9:00 时两人分别在两端,;17:00 时位置对调,。只要两人的位置连续变化, 也连续。一个连续函数从负值变成正值,中途必定有 的时刻;那一刻两人的位置相同。

两天的位置曲线在同一时刻和同一位置相交
两条曲线不需要是直线,也不要求始终单调。共同的端点关系与连续性,已经足以保证至少一次相交。

不过,证明里每句话都有分量。两天得有可比较的同一段钟表时间;走的得是同一条路;移动不能突然跳过某处。如果星期二凌晨就走完了,时间不再重叠;如果回程换了路,“离 一样远”也未必是同一个地方;如果允许瞬移,连续性便没了。一个看似短短的定理,背后仍是我们亲手划出的边界与假设。

阈值分析:配送车与定时闸门

再看一个必须在两个动作之间选的情境。一辆小型自动配送车正靠近校园服务闸门,控制器告诉它:闸门再过 秒就开始关。它还在入口外,要么现在刹住,要么继续走、赶在关门前让整辆车通过。如果车恰好处在“再近就来不及舒适刹停”的位置,闸门至少还要开多久,继续通行才说得通? 这里只是在纸上练习建模,绝不是实际闸门的安全参数;真正设备还要做障碍检测、故障安全设计和现场验证。

收到刹车指令到开始减速,并不是零时间。设延迟为 ,这段时间车以速度 先走了 ;之后若以近似恒定的减速度 刹停,还需要 米。两段加起来,舒适停车距离为 。如果车正好在这个距离边界,选择以恒速继续驶向入口,所需时间是

但车头到达入口,不等于整辆车已经出去。闸门区若有 米深,车身长 米,从车头进入到车尾离开,还需要约 。所以,在我们假定的恒速通行方案下,闸门开放时间必须满足 。真实控制器也许会另设“保持通道清空”的阶段;无论如何,模型不能把抵达入口和完整离开混成同一件事。

代一组演示数值: 秒、 米/秒、 米/秒²、 米、 米。到入口要 秒,车尾离开还要 秒,加起来是 秒。每一项都应当是时间单位。先别把这个数当安全线:刹车弱一点、车身长一点、指令晚一点,会怎样?若闸门内出现障碍,正确动作是触发安全响应,而不是拿更乐观的公式说服自己继续走。

自动配送车接近定时闸门时的停车或通行阈值
决策比较的是剩余开放时间与两段所需时间:先到达入口,再让整辆车完全离开闸门区域。

这三个例子用的是三种不同的数学眼光,但并没有脱离我们前面那一轮建模步骤。到了竞赛,一道题可能同时有数据、好几个小问、互相依赖的任务和论文写作要求。先把这些东西理顺,再去挑软件和算法。

竞赛选题、工具使用、论文阅读、可视化复现、算法扩展与 AI 辅助工作流,已经独立整理到第二篇博客 Competition Techniques。这一篇先把建模基础收完整,最后换一道新的决策题,看看前面的思路能否迁移过去。

自习室案例

最后换个没在前面算过的问题,看你能不能自己把方法带过去。假设图书馆说:“考试周自习室老是满,我们想做一个最好的使用模型。”先别搜索优化算法,问管理员三个问题:您究竟能改开放时长、预约规则、房间分配,还是房间数量?您更在意被拒绝的人数、等待时间、学生满意度,还是房间空着的时数?明早必须作决定时,手里已经有哪些数据?这三个问题不清楚,“最好”就没有明确含义。

假设管理员回答:“明早决定三间自习室各延长多少开放时间,每间最多两小时,总共最多增加六个工作人员小时,希望少拒绝一些学生。”再假设每间开放的房间都由一名工作人员照看。现在我们知道边界至少包括学生到来、预约、房间和工作人员。令 表示房间 多开放几小时,那么 ;三间房所需的额外工作人员小时合计就是 。每小时有多少人在等,是会变化的状态;过去的预约时间是数据;减少被拒人数是可量的目标。到这里,我们还没挑优化器,模型已经开始成形。

三间自习室在共同工作人员时数约束下分配额外开放时间
决策变量控制各房间延长多久;被拒人数与空置房间时数,则从两个方向检验新增容量有没有真正被用好。

先做个很粗的小估算:如果一间房多开两小时,刚好只能接一组新的两小时预约,那么三间各多开两小时,就有接待三组的额外容量。但容量不等于实际有人预约;也只有在每组都占满两小时的假设下,这个估算才成立。若历史记录显示第三间关门后从来没人预约,给它加时可能白白耗人力;若二十个人同时来、每组只预约一小时,“两小时一组”又会把容量算错。正是这些观察告诉我们,下一版该看预约时长、小时级的到来高峰,还是更灵活的安排规则。

怎样检验建议?拿上周或上学期考试周的记录,让现行安排与延时方案在同样的日子各运行一遍,比较会拒绝多少人,同时报告新增开放时间里有多少小时其实没人用。这里还要保持谦虚:房间开放得更久,学生也可能改变预约习惯,历史回放不能替代真实试行;考试高峰更忙的情景也值得测。最后给管理员的建议也许是:“先给一、二号房加时,每小时记录被拒人数,一周后再调整。”它没喊“全局最优”,却更容易执行和检验。

临走前,把它和保温箱放在一起看。两者都从一句模糊的请求出发,找到了会变化的量——这里是等候学生数,那里是蓄冷体温度——也都有一道不能越过的线,并且都需要设计能推翻建议的测试。但两者不一样:瓶子不会发现箱子更暖就改变行为,学生却可能因为开放时间改变而重新安排预约。物理守恒给了保温箱一个很强的起点;涉及人的选择时,我们更需要观察反馈。会建模,不仅是会套用一张流程图,也要知道这个类比走到哪里就不再适用。

总结与可迁移原则

今天我们从班车聊到保温箱,中间还在滑雪场停了一会儿,然后又去了食堂和图书馆。这些例子放在一起,可能还没有在你心里排成一条整齐的线。也许有些地方你觉得太简单,不明白为什么要花这么多时间;也许某一步你得停下来想很久。两种感觉都很正常。毕竟这是第一篇博客,我们还没有正式学习那些有名字的模型。第一次试着从一件现实中的事里找出问题、挑选变量、说明假设,再追问答案靠不靠谱,本来就需要一点时间适应。别让某一道暂时没想通的例题吓住你。

如果读完后只带走一件事,我希望是你对“数学建模”这四个字多了一点自己的理解。数学帮我们把话说准确:什么在变化,哪些量彼此有关,一个结论为什么成立。建模则是先认真听懂现实中的问题,再为这个问题搭一个可以推理的小世界;我们知道它省略了什么,也愿意用观察和数据检验它。一个算得漂亮的答案,如果答非所问,或经不起检验,就还没有完成这件事。今天不用记住每个例子的数字;开始留意问题、边界、假设和证据,就已经是很好的起点。

后面的博客会慢慢介绍具体的模型和方法,我们到时再一步步学。今天先到这里。关上电脑,休息一下吧。

课后测验

下面的十道题会从基本识别逐步走向综合推理。有些是单选,有些是多选,提交前请看清题卡上的说明。题目中的难度百分比是设计目标,不是已经收集的学生统计:第一题希望约 90% 的认真读者能做对,最后一题则是为约 10% 的挑战难度设计的。

  • 标题: 1 - 从现实问题到数学模型
  • 作者: Gavin0576
  • 创建于 : 2026-09-14 20:00:16
  • 更新于 : 2026-10-23 19:41:29
  • 链接: https://jiangpf2022.github.io/blog/2026/09/14/Mathematical-Modeling-01-From-Reality-to-a-Model-zh/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论