案例074 30/40/50 单的阶梯奖
案例074 30/40/50 单的阶梯奖
摘要:日单量 30 单奖 25 元、40 单奖 60 元、50 单奖 120 元,取最高档不叠加。当日已跑 34 单,剩余 3 h 只能再跑 12 单,上限 46 单。三档奖金写成增量形式 \(25z_1+35z_2+60z_3\) 并配 \(z_1\ge z_2\ge z_3\),Gurobi 给出补跑 6 单、共 40 单的最优解:拿 40 档 60 元,当日增量收益 53.30 元,比稳在 34 单多 28.30 元。50 档需 50 单,比上限多 4 单,结构性不可达。若直接写 \(25z_1+60z_2+120z_3\) 且不做互斥,同一方案被算成 78.3 元,虚高 25 元。
关键词:阶梯奖励;增量建模;互斥约束;混合整数规划;临界分析
1 问题提出
1.1 今天还差多少单
平台的冲单奖是阶梯式的:跑满 30 单给 25 元,40 单给 60 元,50 单给 120 元,只取最高一档,不叠加。外卖小哥此刻已送 34 单——30 档其实已经到手,白拿 25 元。剩下三小时,路况熟的情况下最多再跑 12 单,天花板 46 单。于是问题只剩一句:还跑不跑,跑到哪一档?
跑 6 单够 40 档,多拿 35 元;跑 16 单够 50 档,再多拿 60 元——第二件事今天已经不可能。而表格里 12 张候选单的净收益差别极大:近单 6 元上下,远单从第 7 单起就倒贴。
表 1 剩余 3 h 的候选订单(净收益 = 毛收入 − 远单折价)
| 订单 | 距离/km | 用时/min | 毛收入/元 | 折价/元 | 净收益/元 | 入选 | |---|---|---|---|---|---|---| | R01 | 1.2 | 12 | 9.0 | 2.6 | 6.40 | ✓ | | R02 | 1.6 | 13 | 9.2 | 3.1 | 6.10 | ✓ | | R03 | 2.0 | 13 | 9.1 | 3.3 | 5.80 | ✓ | | R04 | 2.3 | 14 | 9.0 | 3.6 | 5.40 | ✓ | | R05 | 2.8 | 14 | 8.8 | 3.8 | 5.00 | ✓ | | R06 | 3.1 | 15 | 8.6 | 4.0 | 4.60 | ✓ | | F07 | 4.2 | 15 | 8.4 | 8.6 | -0.20 | | | F07—F12 | 4.2—7.2 | 15—17 | 7.4—8.4 | 8.6—11.2 | -0.20…-3.80 | |1.2 三条为什么要算
第一,拿几档不等于加几档奖金:阶梯奖是累积值,把三档直接相加会把低档的钱再数一遍;第二,够不够得着要算时间账:50 档还差 16 单,3 h 只装得下 12 单;第三,冲刺本身有成本:多干三小时要付体力、油耗和晚饭,还得接一串净收益为负的远单。这三条分别对应奖金系数、门槛约束和目标里的 \(F y\)。
1.3 Gurobi 怎么解
12 个选单 0-1 变量、3 个档位变量、1 个开工变量,共 16 个 0-1 变量,约束 19 条,分支定界 0.01 秒收敛;真正耗时的是扫描:全案求解 45 个 MILP,共 1.6 秒。
2 数学模型
\(x_i\in\{0,1\}\) 表示是否接第 \(i\) 单(\(i=1,\dots,12\)),\(v_i\) 为其净收益;\(z_1,z_2,z_3\in\{0,1\}\) 表示是否达到 30/40/50 档;\(y\in\{0,1\}\) 表示是否继续干三小时;\(t_i\) 为用时,\(F\) 为三小时机会成本,\(N_0=34\) 为已跑单量。
2.2 目标函数(增量形式)
三档奖金 25、60、120 元是累计值,相邻两档之差才是新到手的钱:25、35、60 元。目标必须按增量写:
系数 \(25,35,60\) 都是“从零到该档”的累计额,因此必须配单调约束;否则 \(z_2=1\) 而 \(z_1=0\) 这种跳档领取会凭空多出 35 元。
2.3 约束条件
档位与单量的联动写成一条门槛递增的式子,每上一档右端加 10:
\(z_3=1\) 时右端 \(=50\);\(z_1=z_2=1,z_3=0\) 时右端 \(=40\)。再补单调、工时与开工联动:
式 (3) 是增量写法的开关:够 40 档必然够 30 档。式 (4) 把三小时折成 180 分钟,候选单合计 177 分钟刚好卡满;\(F\) 只在 \(y=1\) 时出现一次,不按单摊。
2.4 两种替代写法与它们的毛病
写法甲(错误):保留原档金额、只加单调约束——
够 40 档时 \(z_1=z_2=1\),奖金被算成 \(25+60=85\) 元而真实只有 60 元,重复计了 25 元;若 50 档可达更糟:\(25+60+120=205\) 元对 120 元,虚高 85 元。
写法乙(互斥):改回原档金额,并要求只选一档——
式 (6) 与式 (1)—(4) 等价(两模型最优值差 0.0e+00 元)。两种都对,但不能混:增量系数配互斥、原档金额配单调,都会算错。
3 Gurobi 求解实现
3.1 建模要点
bon = 25*z[0] + 35*z[1] + 60*z[2] # 增量,不是 25/60/120
m.addConstr(quicksum(x) + 34 >= 30*z[0] + 10*z[1] + 10*z[2])
m.addConstr(z[0] >= z[1]); m.addConstr(z[1] >= z[2]) # 跳档保护
m.setObjective(quicksum(v[i]*x[i]) - F*y + bon, GRB.MAXIMIZE)
一条实现细节:用 \(x_i\le y\) 把开工变量和选单绑起来。若省掉 \(y\)、把 \(F\) 按单平摊,模型会认为“少跑一单就省一点成本”,从而永远选零单,结论完全相反。
表 2 四种写法的求解结果对比
| 方案 | 补单数 | 当日单量 | 档次 | 奖金/元 | 成本/元 | 净收益/元 | |---|---|---|---|---|---|---| | 稳在 34 单 | 0 | 34 | 30 档 | 25 | 0.0 | 25.00 | | 冲到 40 单(增量) | 6 | 40 | 40 档 | 60 | 40 | 53.30 | | 顶满 46 单(增量) | 12 | 46 | 40 档 | 60 | 40 | 41.10 | | 冲到 40 单(直接相加) | 6 | 40 | 40 档 | 85 | 40 | 78.30 | | 冲到 50 单 | — | 需 50 | 不可达 | — | — | — |最优解补 6 单(前 6 个近单),单净合计 33.30 元,加 40 档奖金 60 元、扣机会成本 40 元,共 53.30 元。顶满 12 单反落到 41.10 元:后 6 单净收益合计 -12.20 元,奖金一分不多,白跑。
4 结果分析
4.1 台阶结构与方案对比

图 1 阶梯奖金曲线与增量拆解:30/40/50 三档的跳跃
图 1 是“取最高档”的真面目:三个平台、跳三次。34→40 单奖金从 25 跳到 60,增量 35 元;40→50 单再跳 60 元。图上两段双箭头正是式 (1) 里 $35z_2$ 与 $60z_3$ 的几何来源;灰区(>46 单)是今天到不了的地方。
图 2 单量—增量收益散点(气泡=该单边际净收益),标出三个断点
图 2 逐点画出 34 到 46 单的边界。34—39 单这一段整体压在零线下方:跑一单净赚 6.4 元,却要先摊 40 元班次成本,**跑了不如回家**;到 40 单被 35 元奖金一把拽到 53.3 元,这就是断点。气泡在 40 单后迅速变小变暗,边际净收益从 6.4 掉到 -3.8 元。最优解(星号)落在断点上,而非最右端。
图 3 稳在 34 单 / 冲 40 / 顶满 46 / 直接相加 四方案对比
四个柱子的排序说明一切:冲 40 单 53.3 元 > 顶满 46 单 41.1 元 > 稳在 34 单 25.0 元 > 错误写法的 78.3 元(假的)。稳与冲之差 28.3 元 = 35 元增量奖金 + 33.3 元单收入 − 40 元机会成本。顶满更差,因为第 7—12 单合计 -12.2 元,抵不过夜里三小时的体力折价。
图 4 剩余 3 h 的累计单量与 40/50 档位线
图 4 是时间轴上的账:按实际用时累加,第 96 分钟(1.6 h)越过 40 档线,此后每一单都在多跑不多拿的区间。50 档线横在 50,曲线最高只到 46,差 4 单,按平均 14.8 分钟一单还需 59 分钟,而 180 分钟已被 12 单占去 177 分钟。4.2 灵敏度:奖金多少、成本多高才值得冲

图 5 40 档奖金 × 最优收益(双轴:补单数阶梯)
图 5 把 40 档奖金从 25 拉到 100 元:左轴最优收益,右轴补单数。补单数在 $A_2^{\ast}=31.7$ 元处从 0 跳到 6,这就是临界线——读法很直白:40 档奖金的增量(\(A_2-25\))要盖住“补 6 单的机会成本减去这 6 单的净收入”。本案 \(A_2=60\) 元远高于 31.7 元,冲是稳赚;若平台把 40 档压到 31 元(增量只剩 6 元),就该收工。

图 6 可跑单量 × 40 档奖金 的最优档位热图
图 6 是二维决策地图。可跑 8~12 单时,40 档奖金 25 元只值 1 档、45 元以上才升 2 档;最末一行(16 单,约 4.3 h)几乎整行是 3 档——**多出的 4 单把 50 档从不可达变成可达**,比调奖金有效得多。唯一例外是 100 元那格掉回 2 档:此时 50 档相对 40 档的增量只剩 20 元,不值再多跑 10 单。
图 7 三小时机会成本 × 最优收益与档位(第三维)
图 7 把 $F$ 当自变量:收益曲线在 $F^{\ast}=68.3$ 元处与稳在 34 单的水平线相交,右侧档位从 2 掉回 1。本案 $F=40$ 元(每小时 13.3 元的体力与油耗),离临界还有 28.3 元余量,结论不脆弱。
图 8 单量—收益前沿与不可行阴影(50 档整块不可达)
图 8 的实线是前沿,虚线是“假如奖金恒为 25 元”的对照——两线在 40 单处的垂直落差 -5.0 元就是阶梯奖的全部价值,粉色区则是“跑了还不如回家”的地带。120 元横线从头到尾没被碰到,右侧灰区(46 单以上)整体不可行。**这就是“50 档不用算”的正式理由**:不是不划算,而是可行域里没有它。
图 9 三小时内可跑单量的分布与累积概率
图 9 承认不确定性:三小时能跑几单本身随机(按 $\lambda=11$ 的泊松到达抽 4000 次、截断在 12 单)。够 40 档(补满 6 单)的概率 96.4%,够 50 档的概率 0.0%——连抽样都撞不到。最优策略的期望奖金 58.73 元,比死守 30 档的 25 元高 33.73 元。
图 10 四方案的边际贡献堆叠:补单净收益、档次奖金与冲刺成本
图 10 把每个方案拆三层:蓝是补单净收益、黄是档次奖金、红是冲刺成本。冲 40 单是 33.3 + 60 − 40 = 53.3;顶满 46 单第二层一分没变、第一层缩到 21.1,整体矮了 12.2 元。错误写法那根最刺眼:奖金层凭空多出 25 元,**模型没错、约束没错,只是系数写错一格**。5 结论
(1)今天的最优动作是补 6 单、够 40 档:增量收益 53.30 元,比稳在 34 单多 28.30 元。这 6 单净赚 33.30 元,加 35 元增量奖金、扣 40 元机会成本,每单边际奖励 5.83 元,接近一单的平均净收益,必须走。
(2)50 档不是“不划算”,是“不可达”:上限 46 单,差 4 单(约 59 分钟),而 3 h 已被 12 单占满。要够 50 档只能把可跑单量从 12 提到 16,靠提前开工,不能靠跑得更快。
(3)顶尖满 12 单是陷阱:第 7 单起净收益转负,合计 -12.2 元,奖金一分不多。收益曲线的峰值在 40 单,不在最右端。
(4)增量形式是核心:式 (1) 的 \(25,35,60\) 与式 (2) 的 \(30,10,10\) 必须同构——前者是台阶高度、后者是台阶位置。直接写 \(25z_1+60z_2+120z_3\) 会虚高 25 元(40 档)或 85 元(50 档);改用互斥约束 \(\sum_k z_k\le 1\) 同样正确,但不能与增量系数混用。
(5)鲁棒区间已量化:40 档奖金高于 31.7 元、三小时成本低于 68.3 元,冲 40 档就成立。本案两数是 60 元与 40 元,余量 28.3 元与 28.3 元,除非晚上下雨单量骤降,这个决定不必重算。
参考文献
[1] Gurobi Optimization LLC. Gurobi Optimizer Reference Manual[Z]. 2024.
[2] Kellerer H, Pferschy U, Pisinger D. Knapsack Problems[M]. Berlin: Springer, 2004.
[3] Martello S, Toth P. Knapsack Problems: Algorithms and Computer Implementations[M]. Chichester: John Wiley & Sons, 1990.
[4] 司守奎, 孙玺菁. 数学建模算法与应用[M]. 3 版. 北京: 国防工业出版社, 2021.
复现方式:python batch_074.py;数据与结果见同目录 .csv / .json,图见 figs/

浙公网安备 33010602011771号