案例 078 首单奖与连续在线奖

案例 078 首单奖与连续在线奖

摘要:平台挂了两个奖励:早 7 点前跑首单给 8 元,连续在线 4 h 给 15 元;早起折算成本 5 元。两个奖励看上去互不相干,实际是嵌套的——早班必须落在连续段之内(\(a\le c\))。写成两个独立约束,模型会给出"拿了首单奖却只在线 1 h"的假解 18.81 元;补上 \(a\le c\) 后同一场景只剩 15.81 元,虚高 3.00 元,被平台追回 8 元后倒比不报名还少 5 元。完整模型的最优解是 184.0 元:10.50 小时全在线,首单奖与连续奖一起拿。四组合对比显示"都拿"确实最优,但它对"只连续"的领先只有 3.0 元——首单奖扣掉 5 元早起成本后净贡献不过 3 元,占净收益的 1.6%。

关键词:嵌套依赖;0-1 逻辑约束;奖励门槛;阶跃灵敏度;可行性审计

1 问题提出

1.1 问题是什么

一条街上的外卖小哥每天有 10.5 小时可以上线,平均每小时出 3.1 单、每单 5.1 元,折成劳动收入 15.81 元/h。平台当天挂两条奖励,条款写在两张不同的海报上:

  • 首单奖:7 点前完成当日首单,奖 8 元。代价是早起,折算成本 5 元(睡眠、早餐、通勤提前)。
  • 连续在线奖:连续在线满 4 h 且在段内跨越午高峰(11:30—13:30),奖 15 元。

表 1 条款要素与折算口径(金额单位:元)

条款 触发条件 金额 折算成本 净贡献 模型变量
首单奖 7 点前完成当日首单 8.0 5.0(早起) 3.0 \(a\)
连续在线奖 连续 4 h 且跨午高峰 15.0 0.0 15.0 \(c\)
劳动收入 每在线 1 h 出 3.1 单 15.81/h 0.0 15.81/h \(h\)
嵌套依赖 早班必在连续段内 — — — \(a\le c\)

表 1 第四行是本案例的全部难点:"早班"不是一个独立可选项,它是"连续段"的子集。谁在 7 点前上线,谁就必须一直在线上待到这段连续时长收尾;两个奖励不是"加法关系",是"包含关系"。

1.2 为什么要优化

第一,奖励是一次性转移,劳动收入是边际量,两者的量纲不同,人脑很容易把 8 元、15 元当成"每小时多 8 元、15 元"来算,从而高估奖励、低估在线时长。第二,门槛会把可行域切碎。4 h 的门槛看起来只是"多待 3 小时",但它与"7 点前首单"叠加后,把连续段的起点钉死在 6:00、终点钉死在 13:30——条款门槛 4 h 在时间轴上被顶成 7.5 h。第三,漏写一条逻辑约束不会有任何报错。\(a\le c\) 漏掉时,模型照样求解、照样给出最优值,只有把时间卡紧,假解才会浮出来(见 4.3 节)。这类"静默错误"比 infeasible 危险得多。

1.3 Gurobi 如何求解

决策只有三个:\(a\)、\(c\) 两个 0-1 变量与一个连续变量 \(h\)。单次求解在根节点就收敛,墙钟不到 0.05 s。真正的工作量在扫描:门槛 7 点、奖金 6 点、二维网格 20 点、四组合 4 点、假解对照 2 点,共 40 次求解,全部墙钟 2 s。因为模型极小,本文所有对比都直接改约束重解,不用对偶值推。

2 数学模型

\(h\) 为当日在线小时,\(a\in\{0,1\}\) 表示是否跑早班,\(c\in\{0,1\}\) 表示是否完成连续段,\(\bar{T}\) 为条款门槛,\(\bar{h}\) 为在线上限。

2.1 目标函数

\[\max\ Z=8a+15c+5.1\times 3.1\,h-5a\tag{1} \]

式 (1) 里 8 元与 15 元都是一次性的,只有 \(5.1\times 3.1h=15.81h\) 随小时线性增长。这个结构决定了后面的全部结论:奖励改变的是"值不值得上线",不改变"上线后每小时值多少",所以只要上限松,最优时长就永远顶在上限上。

2.2 约束条件

\[h\ge 4c,\qquad h\le 10.5\tag{2} \]

\[a\le c\tag{3} \]

\[a,c\in\{0,1\},\qquad h\ge 0\tag{4} \]

式 (2) 是条款原文:连续段至少 4 h,全天不超过 10.5 h。式 (3) 是本案例的核心——早班必须落在连续段内。它不是"额外的好意",而是条款的语法:首单奖要求"7 点前上线",连续奖要求"连续在线",两条叠加意味着 7 点前的那一小时已经被算进连续段,不能单独存在。式 (4) 是变量域。

2.3 时间轴上的真实门槛

\[h\ge 7.5\,c,\qquad 7.5=13.5-6.0\tag{5} \]

\[h_{\min}(c)=\begin{cases}\max\left(\bar{T},7.5\right), & c=1\\ 0, & c=0\end{cases}\tag{6} \]

式 (5) 把条款翻成时间轴:连续段必须从 6:00 开始(否则赶不上首单奖窗)、必须在 13:30 之后结束(否则跨不过午高峰),于是段长下界是 \(13.5-6.0=7.5\) h,而不是条款写的 4 h。式 (6) 给出"拿奖所需的最短开工时长":\(c=1\) 时它等于 \(\max(\bar{T},7.5)\),\(c=0\) 时为 0。这个分段函数就是图 5 右轴那条阶梯的解析形式,也是"门槛在 4 到 7.5 之间怎么调都不动"的原因。

2.4 规模与性质

3 个决策变量、4 条约束,规模可以忽略;性质上它是纯逻辑的 0-1 组合问题:\(h\) 的最优值由"\(c\) 取 0 还是 1"决定,而 \(c\) 的取舍由 \(15-15.81\times(7.5-h^{\circ})\) 的正负决定。所以整张解空间只有 4 个点(图 3 的四根柱),不存在内点最优。

2.5 漏掉嵌套约束后的模型

\[\max\ Z=8a+15c+15.81\,h-5a\quad \mathrm{s.t.}\ h\ge 4c,\ h\le 10.5\tag{7} \]

式 (7) 是反面教材:删掉 \(a\le c\),\(a\) 与 \(c\) 各自独立。它在本案例的基准参数下恰好也给出 184.0 元(因为 \(c\) 本来就取 1),错误被掩盖;一旦当天只剩 1 h 可用,它立刻报出 \(a=1,c=0,h=1\) 的 18.81 元。这是最典型的静默错误:最优值对正确,可行域错。

3 Gurobi 求解实现

3.1 建模要点

核心三行:

a = m.addVar(vtype=GRB.BINARY); c = m.addVar(vtype=GRB.BINARY)
h = m.addVar(lb=0, ub=min(HMAX, hcap))
m.addConstr(h >= max(T, 7.5) * c)   # 条款门槛与时间轴几何合并
m.addConstr(a <= c)                 # 嵌套依赖,写成一条,不要分散
m.setObjective((B1 - E1) * a + B2 * c + R0 * h, GRB.MAXIMIZE)

第一个细节:\(h\ge 4c\) 与 \(h\ge 7.5c\) 不必都写。\(7.5c\) 更强,直接写它;但如果只写 4 h 而忘了时间轴,模型会允许"6:00 上线、10:00 收工"的段,而这段根本没跨过午高峰,属于把条款读漏了。第二个细节:\(a\le c\) 必须写成一条约束,不能写成"\(a\) 的可行域是 \(c=1\)"再加一条别的——分散写容易出现"某条分支漏改"的漏洞。第三个细节:假解对照要把 link 做成开关,用同一个函数、同一份数据、只翻一个布尔量,才能保证两次求解的差异只来自那条约束。

3.2 求解结果

表 2 四种 0-1 组合的净收益(金额单位:元)

组合 \(a\) \(c\) 在线小时 劳动收入 奖励 净收益 判定
都不拿 0 0 10.50 166.0 0.0 166.0 可行
只首单 1 0 — — 8.0 — 违反 \(a\le c\)
只连续 0 1 10.50 166.0 15.0 181.0 可行
两个都拿 1 1 10.50 166.0 23.0 184.0 最优

表 2 是全部答案。四行里第二行不可行,这正是本案例的教学点;第四行 184.0 元最优,比第三行只多 3.0 元。"都拿"确实是最优,但优势薄得像一张纸:首单奖 8 元减去 5 元早起成本,净贡献 3.0 元,只占净收益的 1.6%。若早起成本涨到 8 元(多睡一小时的价值),这个优势就归零——等价于图 7 里首单奖跌回 5 元的那道台阶。

4 结果分析

图 1 奖励条款的时间轴与嵌套关系:早班窗嵌在连续段之内

4.1 结构:条款的时间轴形态 图 1 把三条信息叠在一根时间轴上:橙色带是 7 点前的首单奖窗,蓝色带是 11:30—13:30 的午高峰,两根棒棒糖分别是 8 元与 15 元,灰色矮棒是 5 元早起成本。箭头标出 \(a\le c\) 的方向:早班不是独立的一段,它落在连续段内部。看懂这张图,就等于看懂了"为什么 4 h 的门槛会变成 7.5 h"——段要同时罩住 6:00 的首单和 13:30 的午高峰末,长度被两头夹住。

图 2 在线小时与净收益:4 h 是条款门槛,7.5 h 才是真正可拿奖的最短段

4.2 小时—净收益:两条平行线 图 2 的三条线在 7.5 h 处同时起跳:不拿奖的线从原点直线上升,只连续奖的线在 7.5 h 处跳 15 元,都拿的线跳 18 元。两条奖励线是平行的,间距恒为 3 元——这就是首单奖的全部净贡献。图里 4 h 的竖线(条款门槛)与 7.5 h 的竖线(跨高峰最短段)相距 3.5 h,中间的区间是"看起来够门槛、实际拿不到奖"的陷阱带。

图 3 四种 0-1 组合与漏约束假解:只首单在 a ≤ c 下不可行

4.3 四组合与假解 图 3 是主图。五根柱:都不拿 166.0 元、只首单不可行(违反 \(a\le c\))、只连续 181.0 元、都拿 184.0 元、以及最右边那根矮柱——漏掉 \(a\le c\) 后在"只有 1 h"场景下算出的假解 18.81 元。假解看起来小,是因为它偷偷把 10.5 h 缩成 1 h;把它和"老老实实跑 1 小时"的 15.81 元比,账面虚高 3.00 元(正好是 8−5);平台核验连续时长后追回 8 元,实际到手 10.81 元,比不报名还少 5 元。假解的危害不在数值大小,在于它把"不可行的方案"包装成了"最优方案"。

图 4 当日时序:连续段 7.5 h 跨午高峰,晚段补 3 h,累计收益阶梯上行

4.4 时序:一天的形状 图 4 上半是在线段:6:00 上线,一连 7.5 h 到 13:30,中间跨过午高峰;休息 3 h 后 16:30 再上,19:30 收工,合计 10.5 h。下半是累计净收益:6:00 先掉 5 元(早起成本),6:30 首单完成跳 8 元,之后每半小时稳定 +7.9 元,13:30 段满再跳 15 元,收工在 184.0 元。奖励的两级台阶在累计曲线上是两道明显的竖线,它们的斜率是无穷大,而劳动收入的斜率恒为 15.81 元/h——两种钱的性质完全不同。

图 5 连续奖门槛扫描:净收益在 10.5 h 处阶跃下掉,最短开工时长阶梯上抬

4.5 主灵敏度:门槛扫描 图 5 横轴是连续奖门槛,从 3 h 扫到 11.5 h。左轴净收益在 3—10.5 h 之间完全不动(恒为 184.0 元),到 11.5 h 一步掉 18.0 元;右轴"拿奖所需最短开工时长"在 3—6 h 之间被时间轴钉在 7.5 h 不动,8 h 处抬到 8,10.5 h 处抬到 10.5。两条曲线都是阶梯,没有一段是斜的:门槛从 3 调到 4,骑手什么都不用改;从 6 调到 8,才真的要多待 0.5 h。这就是"离散跳变"的含义——参数连续地变,解只在几个点上变。

图 6 可用时长与门槛的二维网格:左下角无奖区,右上角可行

4.6 二维:可用时长 x 门槛 图 6 是 5x4 的网格。左下角(可用 1—6 h)全部落在"无奖区":无论门槛是 3 还是 6,只要当天凑不出 7.5 h 的连续段,15 元一分拿不到,收益只剩 15.81—94.86 元的纯劳动收入。跨过 7.5 h 的红线后,整行突然跳到 184.0 元量级。这张图说明"门槛 4 h"是个伪参数:真正的分界线是横着的那条 7.5 h,不是竖着的任何一条。

图 7 首单奖额扫描:金额线性变化,跑不跑早班是 0/1 阶跃

4.7 第三维:首单奖额 图 7 把首单奖从 3 元扫到 14 元。净收益是一条斜率 1 的直线(181.0 元到 190.0 元),但右轴的 \(a\) 在 5 元处是一道垂直的台阶:\(B<5\) 时早起亏本,\(a\) 从 1 掉到 0。金额是连续的,参与是离散的——这是所有"门槛型激励"的共同形状,也是本案例与普通定价问题的分野。

图 8 时长—净收益前沿与两段不可行区

4.8 前沿与不可行区 图 8 横轴在线小时,三条前沿在 7.5 h 处一起向上跳 18/15/0 元。左侧灰色区(\(h<7.5\))里三条线重合,因为奖励全拿不到;右侧粉色区(\(h>10.5\))不可行。帕累托前沿在这里是"两段直线 + 一个断点",没有曲率,也没有权衡:多跑一小时永远多赚 15.81 元,直到撞上 10.5 h 的硬墙。

图 9 单量波动下的净收益分布

4.9 分布:单量波动 图 9 给单量密度加 7% 的正态扰动,跑 4000 次。净收益均值 184.0 元、标准差 11.7 元、P5 164.2 元、P95 202.8 元。均值与确定性解 184.0 元几乎重合,因为奖励是常数、劳动收入对密度是线性的,期望不被扭曲;但两端拉开 38.6 元,这才是"今天能赚多少"的真实口径。奖励 23 元在这里的作用是抬高整条分布,而不是压缩波动。

图 10 净收益的条款分解:劳动收入 166 元,奖励 23 元,成本 5 元

4.10 净收益分解 图 10 把 184.0 元拆成四块:劳动收入 166.0 元、首单奖 8 元、连续奖 15 元、早起成本 −5 元。奖励合计 23 元,占净收益 12.5%。看上去奖励贡献了一成多,但扣掉成本后的净贡献只有 18 元(9.8%),其中 15 元还绑着 7.5 h 的在线承诺。真正决定收入的仍是那 166.0 元劳动收入——奖励是"把已经在线上的人留住"的工具,不是"让人上线"的理由。

5 结论

  1. 奖励条款是嵌套的,不是并列的。 \(a\le c\) 一条约束就把"早班"锚定在连续段内。漏掉它,基准解的最优值不变(仍是 184.0 元),但可行域已经错了——这就是最危险的静默错误。
  2. 漏约束的假解虚高 3.00 元。 只有 1 h 可用时,假模型报 18.81 元(\(a=1,c=0,h=1\)),真模型只有 15.81 元;追回 8 元首单奖后到手 10.81 元,比不报名少 5 元。虚高的部分正好是"8 元奖金 − 5 元成本"。
  3. "都拿"是最优,但只赢 3.0 元。 184.0 元对 181.0 元。首单奖的净贡献被 5 元早起成本吃掉大半,只占净收益 1.6%;早起成本一旦涨到 8 元,这个优势就归零(图 7 的台阶)。
  4. 4 h 的门槛是伪参数,真门槛是 7.5 h。 6:00 起、13:30 止的时间轴几何把段长下界顶到 7.5 h,门槛在 3—6 h 之间怎么调,最优解一动不动(图 5、图 6)。条款写的数字和条款真正的约束力,差着 3.5 小时。
  5. 阶梯出现在"是否参与"和"最短开工时长"上,不在"最优时长"上。 因为 15.81 > 0,最优时长永远顶在 10.5 h;门槛越过 10.5 h 时,连续奖整块消失,净收益一步掉 18.0 元而时长不变(图 5 右端)。理解这一点,才不会把"多跑一小时"和"多拿一笔奖"混为一谈。

参考文献

[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.

posted @ 2026-11-11 18:05  小青蛙电气  阅读(3)  评论(0)    收藏  举报