案例 056 停在哪个路口等单

案例 056 停在哪个路口等单

摘要:商圈里 12 家商家的派单强度合计 159 单/h,骑手空闲时只能在 10 个候选点里选一个停下等单。等待时间由该点的派单强度决定(\(e_{j}=60/\lambda_{j}\),10—40 单/h 对应 1.50—6.00 min),接单后的空驶时间由该点到商家的距离决定,两者方向相反:路口派单强度最高、但离商家远;店门口一步就到、但单子稀。本文把它写成带覆盖截断的 p-median 0-1 规划:\(x_{j}\) 选点、\(z_{ij}\) 把商家需求指派给点位,\(t_{ij}>R\) 的指派直接禁掉,未覆盖需求按 \(\pi=35\) min 折算流失。10 个候选、12 家商家、120 个指派的模型共求解 53 次、每次 0.01 s 级。结果:死守最旺店门口 71.1% 覆盖、8.94 min;死守最忙路口 71.1% 覆盖、6.70 min;优化单点选 天河路口(78.6% 覆盖、7.40 min);优化双点选 体育西路口 与 黄埔大道口,覆盖 94.3%、周期 6.37 min。派单强度最高的点不是最优解——它只赢了等待那一半,输在覆盖那一半;真正的解要等两个点轮换才同时成立。

关键词:空闲等待点;p-median;最大覆盖;派单强度;骑手选址;灵敏度分析

1 问题提出

1.1 问题是什么

午高峰 11:30—13:00,天河路商圈 12 家商家的出单强度在 7—22 单/h 之间,合计 159 单/h。骑手送完一单后回到空闲状态,此时他要决定"停在哪里刷手机等派单"。候选点有 10 个,分三类:3 个店门口(煲仔饭、茶餐厅、糖水铺)、4 个路口(体育西、天河、环市、黄埔大道)、3 个其他(地铁口、小区门口、商场侧门)。

停在不同地方,账完全不同:

  • 等多久:系统把订单派给"离商家最近且空闲"的骑手,某点被派单的强度 \(\lambda_{j}\) 越高,骑手在该点平均等待越短,\(e_{j}=60/\lambda_{j}\)。路口 \(\lambda\) 最高(体育西 40 单/h,1.50 min),店门口最低(4.62 min)。
  • 跑多远:接到单后要从停车点骑到商家,按 3.0 min/km 的骑行速度折算,9 min 半径内的商家才算"够得着"。
  • 够得着几家:超过半径的商家等于没覆盖,这一单会被别人抢走。

表 1 十个候选等待点的画像($\lambda_{j}$ 为派单强度,$t$ 为 9 min 内可达商家)

编号 位置 类型 \(\lambda_{j}\) /(单/h) \(e_{j}\) /min 加权空驶 /min 可覆盖单量·商家数
S1 煲仔饭门口 店门口 13 4.62 4.3 113/8
S2 茶餐厅门口 店门口 14 4.29 5.1 132/10
S3 糖水铺门口 店门口 10 6.00 5.3 70/5
J1 体育西路口 路口 40 1.50 5.2 113/7
J2 天河路口 路口 36 1.67 5.7 125/9
J3 环市路口 路口 27 2.22 5.7 99/7
J4 黄埔大道口 路口 30 2.00 5.0 91/7
P1 地铁口 其他 23 2.61 5.6 116/9
P2 小区门口 其他 18 3.33 6.1 102/8
P3 商场侧门 其他 21 2.86 5.8 91/7

表 1 已经把矛盾摆在桌面上:\(\lambda\) 最高的体育西路口 \(e\) 只有 1.50 min,但它的加权空驶 5.2 min 也是全场最高之一;三个店门口的空驶短,\(e\) 却要 4—6 min。没有一个点能同时在两列上占优,这就是必须建模的原因。

1.2 为什么要优化

第一,"守在店门口"省的是空驶、赔的是等待。守在单量最旺的 煲仔饭门口,空驶只要 4.32 min,是四方案里最短的;但该点派单强度只有 13 单/h,等待 4.62 min 把优势全吃掉,周期 8.94 min,覆盖率还只有 71.1%。

第二,"守在路口"赢的是等待、赔的是覆盖。守在派单最强的 体育西路口,等待压到 1.50 min,周期 6.70 min 比守店门口快 1.54 min;但该点贴在商圈西侧,东边 M09—M12 四家店全部落在 9 min 圈外,覆盖率仍是 71.1%。快,但是挑单——挑单在平台上等于把单让给别人。

第三,一个点不够。商圈东西 4.6 km、南北 3.5 km,单点覆盖圈最多罩住 9 min 骑行范围,78.6% 已经是单点的天花板(第 4.8 节的前沿会证明)。要么接受 9 单/h 的漏单,要么上两个点轮换。

1.3 Gurobi 如何求解

变量两组:\(x_{j}\in\{0,1\}\) 表示是否把该点纳入轮换,\(z_{ij}\in\{0,1\}\) 表示商家 \(i\) 的需求是否由点位 \(j\) 承接。约束是标准的 p-median 骨架(式 3、式 4),外加一条覆盖截断 \(z_{ij}=0\) 当 \(t_{ij}>R\)——没有这条,模型会把 20 min 车程之外的商家也算成"覆盖",得到一个纸面上漂亮、实际上送不到的解。

目标(式 2)用 \(\pi=35\) min 给未覆盖需求定价:这等价于"漏一单的商誉损失折算成 35 分钟",让覆盖率和周期进入同一个标尺,避免两阶段求解。整个模型 10 个 0-1 选址变量、120 个指派变量、约 34 条约束,Gurobi 每次都在 0.05 s 内证到 gap 0。

2 数学模型

2.1 符号说明

\(I\) 为商家集合(\(|I|=12\)),\(d_{i}\) 为商家 \(i\) 的派单强度(单/h);\(J\) 为候选等待点集合(\(|J|=10\));\(\lambda_{j}\) 为点位 \(j\) 的派单强度(单/h);\(e_{j}\) 为该点的期望等待(min);\(t_{ij}\) 为点位 \(j\) 到商家 \(i\) 的空驶时间(min);\(R\) 为可接受空驶半径(9 min);\(p\) 为轮换点数;\(x_{j},z_{ij}\) 为 0-1 决策变量;\(\pi\) 为未覆盖需求的折时(min)。

2.2 目标函数

\[e_{j}=\frac{60}{\lambda_{j}},\qquad j\in J\tag{1} \]

等待时间与派单强度成反比:派单强度翻倍,平均等待减半。这是排队论 M/M/1 在低负荷下的近似,也是平台派单"就近+轮询"机制的一阶刻画;\(\lambda_{j}\) 由历史派单记录统计得到,是外生参数。

\[\min\ Z=\sum_{i\in I}d_{i}\sum_{j\in J}\left(t_{ij}+e_{j}\right)z_{ij}+\pi\sum_{i\in I}d_{i}\left(1-\sum_{j\in J}z_{ij}\right)\tag{2} \]

第一项是"被服务的需求"的总周期:需求越大、周期越长,权重越大,单位是 单/h × min;第二项是"没被服务"的惩罚。两项相加再除以总需求,就是表 2 的"综合指标",可以直接和"守在店门口"这类基线比大小。

2.3 约束条件

\[\sum_{j\in J}z_{ij}\le 1,\qquad z_{ij}\le x_{j},\qquad z_{ij}=0\quad \text{若}\ t_{ij}>R\tag{3} \]

每个商家最多指派给一个点位(重复指派会把同一份需求算两遍);只有被选中的点位才能承接需求;空驶超过半径的指派直接置零,这就是"最大覆盖"的思路落在 p-median 里的方式。

\[\sum_{j\in J}x_{j}=p,\qquad x_{j}\in\{0,1\}\tag{4} \]

恰好选 \(p\) 个点。\(p=1\) 是单点死守,\(p=2\) 是两点轮换。注意这里没有"每个商家必须被覆盖"的硬约束——商圈边缘的商家本来就该放弃,硬约束会让 \(p=1\) 直接不可行。

\[y_{j}=\frac{\sum_{i\in I}d_{i}z_{ij}}{\sum_{i\in I}\sum_{j\in J}d_{i}z_{ij}},\qquad \lambda_{\mathrm{eff}}=\sum_{j\in J}y_{j}\lambda_{j},\qquad W=\frac{60}{\lambda_{\mathrm{eff}}}\tag{5} \]

两点轮换时,骑手按各点承接的单量比例分配停留时间 \(y_{j}\),等效派单强度是加权和 \(\lambda_{\mathrm{eff}}\),期望等待 \(W=60/\lambda_{\mathrm{eff}}\)。这条式子说明了轮换的真正好处:不是"两个点各等一半时间",而是"两个点的单子都收得到",\(\lambda_{\mathrm{eff}}\) 高于任一点单独的值。

2.4 规模与性质

模型是带覆盖截断的 p-median,10 个选址变量、120 个指派变量、约 34 条约束。LP 松弛不算紧(选址问题的通病),但规模小,分支定界在毫秒级收敛。真正值得说的一句是:\(t_{ij}\) 是用曼哈顿距离乘 3.0 min/km 算的确定性时间,没有随机性;随机性全部收在 \(e_{j}\) 的期望里,所以模型是确定性的 0-1 规划,不需要场景采样。

3 Gurobi 求解实现

3.1 建模要点

覆盖截断在建模时直接落成约束,而不是靠目标函数惩罚,这样求解器不会去试那些注定被禁的指派:

ok = (TT <= R + 1e-9)                       # TT[j,i] 为点位 j 到商家 i 的空驶
for i in range(NM):
    for j in range(NC):
        if not ok[j, i]:
            m.addConstr(z[i, j] == 0)      # 超半径的指派直接禁掉
    m.addConstr(gp.quicksum(z[i, j] for j in range(NC)) <= 1)
for j in range(NC):
    for i in range(NM):
        m.addConstr(z[i, j] <= x[j])        # 没选的点不能接单
m.addConstr(gp.quicksum(x[j] for j in range(NC)) == p)
m.setObjective(PEN * gp.quicksum(DEM[i]*(1 - gp.quicksum(z[i,j] for j in range(NC)))
              for i in range(NM)) + gp.quicksum(DEM[i]*(TT[j,i]+60/lam[j])*z[i,j] ...))

MIPGap 设 1e-9,TimeLimit 8 s,实际从未触发。扫参时把 allow 参数留给"只能从店门口里选 / 只能从路口里选",用它生成两个基线方案,保证基线和优化解用的是同一套目标函数——否则对比不成立。

3.2 求解结果

表 2 四种等单方案的服务水平($\pi=35$ min 折算流失)

方案 点位 覆盖率 /% 等待 /min 空驶 /min 接单周期 /min 综合指标 /min
守店门口 S1 煲仔饭门口 71.1 4.62 4.32 8.94 16.48
守路口 J1 体育西路口 71.1 1.50 5.20 6.70 14.89
优化单点 J2 天河路口 78.6 1.67 5.73 7.40 13.30
优化双点 J1 + J4 94.3 1.73 4.64 6.37 7.99

四行读下来:守店门口综合 16.48 min、守路口 14.89 min、优化单点 13.30 min、优化双点 7.99 min。优化单点比守店门口好 3.18 min、比守路口好 1.59 min;双点再比单点好 5.31 min。 双点的周期 6.37 min 已经低于两个单点方案,覆盖率还高出 15.7 个百分点——这正是式 5 的 \(\lambda_{\mathrm{eff}}\) 在起作用。

4 结果分析

图 1 商圈结构:12 家商家的单量分布、10 个候选等待点与 2 的 9 min 覆盖圈

4.1 商圈结构 图 1 把 12 家商家(圆面积=单量)、10 个候选点(方块=店门口、圆=路口、三角=其他)和优化双点的两个 9 min 覆盖圈画在同一张平面图上。两个圈一个压住西侧的老街片(M01—M06),一个压住东侧的天河片(M07—M12),中间在 天河路口 附近重叠。看这张图就知道为什么单点不够:任何单圈都会漏掉另一头,而两家店的单量分布是"两头重、中间轻",所以必须两头各放一个圈。

图 2 候选点的画像:派单强度、加权空驶时间与 9 min 内可覆盖单量

4.2 候选点画像 图 2 横轴是派单强度 \(\lambda_{j}\)、纵轴是 9 min 内可达商家的加权空驶时间、气泡面积是可覆盖单量。三类点分得很开:路口挤在右侧(\(\lambda=27—40\) 单/h、空驶 5.0—5.7 min),店门口挤在左侧(\(\lambda=10—14\) 单/h、空驶 4.3—5.3 min),其他点居中。路口用两三倍的单量只换来不到 1 min 的空驶优势,这就是"守着路口"最容易被高估的地方。****星标是进入最优解的点:天河路口 落在"高 \(\lambda\)、中等空驶"的膝点上,体育西路口 与 黄埔大道口 分别补上东西两端的覆盖。三个店门口里只有 S2(茶餐厅)进了 p=2 的候选,其余两个只覆盖自己门口那一家店,9 min 圈里没有第二家商家。

图 3 四种等单方案的期望接单周期与需求覆盖率

4.3 四方案对比 图 3 是核心对比。守店门口(煲仔饭门口)周期 8.94 min、覆盖 71.1%;守路口(体育西路口)周期 6.70 min、覆盖 71.1%;优化单点(天河路口)周期 7.40 min、覆盖 78.6%;优化双点周期 6.37 min、覆盖 94.3%。守路口那一根柱子最矮却最"挑食":它把东边四家店的 9 单/h 直接扔掉,才换来 6.70 min 的漂亮平均。优化单点慢了 0.33 min,却多覆盖 7.5 个百分点——这就是 \(\pi=35\) 折算后的取舍。

图 4 四种方案的累计覆盖曲线(横轴为从停车点出发到商家的周期)

4.4 累计覆盖 图 4 把每个方案覆盖到的需求按"从停车点到商家的周期"排序累加,横轴是周期、纵轴是累计覆盖比例。四条曲线的终点就是各自的覆盖率;曲线越靠左、越高越好。优化双点在 8.1 min 处就爬过 80%、8.6 min 收尾;优化单点要到 10.4 min 才到 80%、10.7 min 收尾;守店门口 36% 的单量在 4 min 内到齐,但尾巴一直拖到 11.7 min。这条"爬不上去的尾巴"就是被扔掉的 9 单/h;双点方案没有尾巴,所以它的曲线能一直顶到 100%(分母只算被覆盖的 150 单/h)。

图 5 商圈整体热度对期望接单周期与单点覆盖率的影响

4.5 主灵敏度:整体热度 图 5 左轴是期望接单周期、右轴是单点覆盖率,横轴是商圈整体派单热度 \(\lambda\) 的倍数(0.6—1.4)。双点方案的周期从 7.52 单调降到 5.87 min,覆盖率一直是 94.3%——热度只改变等待,不改变覆盖结构。单点方案则从 8.51 降到 7.40 min 之后在 1.4 倍处回升到 8.17 min,同时覆盖率跳到 83%:多罩住一家远商家,平均周期就被这家店拉长了;平均值的这种"反弹"不是模型出错,是服务范围扩张的代价,看指标必须连覆盖率一起看。

图 6 热度 × 派单强度集中度的期望接单周期热图

4.6 二维:热度 × 集中度 图 6 是 4×5 热图,行是派单强度集中度 \(\gamma\)(\(\lambda_{j}^{\gamma}\) 归一化,\(\gamma\) 越大越向少数点位集中),列是整体热度。最浅的一格 6.65 min(\(\gamma=1.9\)、热度 1.4),最深的一格 8.51 min(\(\gamma=1.0\)、热度 0.6)。同一热度下把 \(\gamma\) 从 1.0 抬到 1.9,前四列降 0.32—0.64 min、最右一列降 1.53 min;同一 \(\gamma\) 下把热度从 0.6 抬到 1.4,\(\gamma\ge1.3\) 的三行降 1.22—1.44 min,而 \(\gamma=1.0\) 那行只降 0.33 min。热度是"量"、集中度是"结构":热度不够时点位之间几乎没有差别,热度上来以后强弱才被放大;而 \(\gamma=1.0\) 那行降得最少,是因为它在 1.4 倍处把远商家纳进覆盖,把降幅又还了回去。

图 7 可接受空驶半径对覆盖率与接单周期的影响(第三维)

4.7 第三维:可接受半径 图 7 横轴是空驶半径 \(R\)(6—12 min),左轴覆盖率、右轴周期。\(R\) 从 6 放到 12,单点覆盖率从 51.6% 升到 95.6%,双点从 73.0% 升到 100.0%;代价是周期从 5.87 涨到 8.06 min。半径的本质是"愿意跑多远换覆盖率":\(R=6\) 时周期最短但漏掉一半单,\(R\ge 10\) 时覆盖率封顶、周期不再恶化,说明本案的 9 min 是"还没封顶但已够用"的折中位置。单点曲线在 8—9 min 处有个下折(从 9.20 掉到 7.40),那是模型从店门口点切到路口点的跳变,离散选址的典型非单调。

图 8 点位数—覆盖率—接单周期前沿,以及覆盖率不达标区

4.8 点位数前沿 图 8 横轴覆盖率、纵轴期望周期,每个点标注点位数 \(p\)。\(p=1\) 落在(78.6%、7.40 min),\(p=2\) 跳到(94.3%、6.37 min),\(p=3\) 起覆盖率封顶 100.0%、周期继续降到 5.51 min。左侧灰区是覆盖率低于 70% 的服务不达标区,\(p=0\)(不设点)根本不在可行域内。这条路的前半段"既快又广",说明第二个点是纯赚;后半段只在时间上抠 0.86 min,性价比断崖式下降——这就是"轮换两点"而不是"轮换五点"的量化依据。

图 9 三种方案的空驶时间分布(按单量加权)

4.9 空驶分布 图 9 是按单量加权的空驶时间分布。守店门口 4 min 内只占 36%、8 min 以上还有 7%;守路口 4 min 内 34%、8 min 以上 0%(它到哪都要骑一段);优化双点 4 min 内 45%、8 min 以上 0%。分布形状比均值更能说明问题:双点方案不是把平均往前挪,而是把长尾砍掉——长尾正是骑手"到了商圈才发现单在另一头"的那种单。

图 10 每增加一个点位的边际新增覆盖单量

4.10 边际贡献 图 10 是每增加一个点位的边际新增覆盖:第 1 个点带来 125 单/h,第 2 个点补 25 单/h,第 3 个点只剩 9 单/h,之后归零(覆盖率已到 100%)。边际收益是断崖式递减的,但第 2 个点是唯一"同时改善两个指标"的一步:覆盖率从 78.6% 跳到 94.3%,周期反而从 7.40 降到 6.37 min。第 3 个点虽然把覆盖率补到 100.0%,周期只再降 0.25 min——这就是"两个点"的量化边界。

5 结论

  1. 等待与空驶是一对反向指标:派单强度最高的 体育西路口(\(\lambda=40\) 单/h、等待 1.50 min)空驶要 5.20 min,店门口 煲仔饭门口(\(\lambda=13\) 单/h、等待 4.62 min)空驶只有 4.32 min。任何单指标排名都会给出错的答案。
  2. 守店门口 8.94 min / 71.1%,守路口 6.70 min / 71.1%,两者覆盖率相同——守路口用 7.5 个百分点的覆盖换 2.2 min 的等待,本质是把东边的单让给了别人。
  3. 优化单点选 天河路口,周期 7.40 min、覆盖 78.6%,综合指标 13.30 min,比两个基线分别好 3.18 与 1.59 min。它不是最快的,但它是在"覆盖不打折"前提下的最快。
  4. 优化双点选 体育西路口 与 黄埔大道口,覆盖 94.3%、周期 6.37 min,轮换共享等待 1.69 min、总周期 6.33 min。第 2 个点用 25 单/h 的边际覆盖换来 15.7 个百分点覆盖率和 1.03 min 周期,两个指标同向改善,"停两个路口轮换"不是权宜之计,而是长条形商圈的正确答案。
  5. 灵敏度给出了三个边界:整体热度涨到 1.4 倍时单点周期反而回升(覆盖扩张的代价);同一热度下集中度只值 0.32—0.64 min,最热那一列才值 1.53 min;空驶半径 \(R\ge 10\) min 后覆盖率封顶。这三个边界共同说明:选址的瓶颈不是等待,而是商圈的几何形状。

参考文献

[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:03  小青蛙电气  阅读(2)  评论(0)    收藏  举报