2026 长三角高校数学建模竞赛 ABC 题全套参考方案,全套代码+思路+助攻论文+结果数据
A 题要求基于历史 6 个月货量预测未来 7 天,并进一步做集包规则与设备购置优化;B 题要求做餐厅交易数据分析、预测、备菜和套餐优化;C 题要求搜集外部数据构建“省超”热度指数、分类和潜力评估。

优惠链接:关注名片,自动回复获取链接
摘要
本文围绕 2026 年第六届长三角高校数学建模竞赛 ABC 三道赛题,给出系统化建模思路与可实现算法框架。A 题针对物流网络集包规则与设备优化问题,构建“货量预测—路由分段—混包聚合—机器/人工选择—设备投资”的混合整数规划模型;B 题针对自助量贩餐厅经营问题,建立“交易分析—需求预测—备菜优化—套餐设计”的数据驱动运营优化框架;C 题针对“谁是下一个苏超”问题,提出基于熵权法、聚类分析、余弦相似度和 TOPSIS 的省超热度与潜力评价模型。三题共同体现了数据预测、运筹优化、指标评价与实际业务解释之间的融合。
三题论文写作建议
A 题论文要突出“数学硬度”:
重点写清楚路由分段变量、混包聚合变量、格口约束、人工/机器成本、设备折旧年化模型。不要只写启发式算法,否则深度不够。
B 题论文要突出“业务闭环”:
从菜品销售规律,到营养需求预测,再到备菜和套餐,最后落到降本增效、减少浪费、提高复购率。
C 题论文要突出“指标体系可信度”:
数据来源要可靠,指标要分层,权重要有依据,聚类解释要能讲清楚“为什么苏超火”。
最推荐的得奖打法
A 题:LightGBM 预测 + MILP/CP-SAT 优化 + 启发式加速 + 敏感性分析。
敏感性分析可以讨论货量增长率、人工工资、机器格口能力变化对总成本和设备购置的影响。
B 题:EDA 可视化 + 多目标预测 + 备菜整数规划 + 套餐组合优化。
可视化越丰富越好,尤其是菜品销量长尾图、菜品共现网络、工作日需求曲线。
C 题:熵权-TOPSIS + KMeans/PCA + 苏超相似度画像。
文章表达要强,可以把苏超总结为“城市联动型群众赛事经济样板”。
如果你准备正式写论文,建议优先选 A 题或 B 题。A 题更像一等奖题,B 题更容易做完整,C 题更依赖数据搜集质量。
2026 长三角高校数学建模竞赛 ABC 题全套参考方案
总体选题建议
如果目标是稳妥拿奖:
A 题最偏运筹优化,技术含量高,容易拉开差距。
核心是“预测 + 网络分段 + 集包规则 + 设备投资”的供应链优化问题。只要把预测模型、混包规则、格口约束、人工/机器成本和设备折旧统一进一个整数规划模型,论文会很硬。
B 题最适合数据分析队伍。
有交易流水、菜品、营养成分,容易做出漂亮可视化和业务建议。模型可用“需求预测 + 菜品组合优化 + 套餐优化”,文章表现力强。
C 题最开放,适合会爬数据、会写指标体系的队伍。
它需要自己搜集省域经济、人口、足球文化、媒体传播、赛事数据。苏超已公开有 85 场比赛、现场观众总数 243.3 万、场均 2.86 万、线上直播观看 22.2 亿等热度数据,可作为热度指数校准锚点。
A 题:物流网络集包规则及设备优化
一、问题重述与核心难点
A 题的本质是一个两阶段供应链网络优化问题:
第一阶段,利用历史 6 个月首分拣—末分拣流向货量,预测未来 7 天每条 OD 流向的小件包裹量。
第二阶段,在给定走货路由下,为每个 OD 流向确定“在哪些分拣中心建包、在哪些分拣中心拆包”,并在每个场地选择机器或人工集包方式,使总成本最低。
第三阶段,考虑未来一年货量每年增长 20%,进一步决定每个分拣中心购买哪些设备、买多少台,以及对应集包规则。
难点有三个:
第一,路由是固定的,但建包路径可选。
例如一条路由为:
A \rightarrow B \rightarrow C \rightarrow D
可选择只在 A 建包、D 拆包;也可选择 A-B、B-D;也可每一段都拆包重建。
第二,混包规则复杂。
同一下一分拣流向的包裹不能被拆散到不同集包中;目的地相同的小件包裹,下一个拆包场地必须一致。
第三,机器格口、人工流向数、产能和成本同时约束。
机器有格口数量和处理能力,人工有最大集包流向数,第三问还要加入设备购置、折旧、人工兜底。
二、A 题完整建模思路
问题 1:货量预测模型
建议采用分层集成预测模型:
对每条 OD 流向 ,设历史日货量为:
y_{r,t}
预测未来 7 天:
\hat{y}_{r,t+1},\ldots,\hat{y}_{r,t+7}
推荐三类模型融合:
- 统计基线模型:移动平均、指数平滑、节假日/星期因子;
- 机器学习模型:LightGBM / XGBoost;
- 层级修正模型:按首分拣、末分拣、全网总量做一致性校正。
特征设计:
| 特征类型 | 变量 |
|---|---|
| 时间特征 | dayofweek、是否周末、月份、日期序号 |
| 滞后特征 | lag1、lag7、lag14、lag28 |
| 滚动特征 | rolling_mean_7、rolling_mean_14、rolling_std_7 |
| OD 特征 | 始发中心、目的中心、路由长度、是否跨区 |
| 层级特征 | 首分拣总量、末分拣总量、全网总量 |
预测结果要做非负修正:
\hat{y}_{r,t}=\max(0,\hat{y}_{r,t})
若题目结果表要求整数,则取:
\tilde{y}_{r,t}=\text{round}(\hat{y}_{r,t})
问题 2:集包规则优化模型
对每条 OD 流向 ,其固定路由为:
P_r=(v_{r,0},v_{r,1},\ldots,v_{r,m_r})
建包路径可以理解为对这条路由做“分段”。
若选择从节点 建包,到节点 拆包,则定义决策变量:
x_{r,p,q}=
\begin{cases}
1, & \text{流向 } r \text{ 在 } v_{r,p} \text{ 建包并在 } v_{r,q} \text{ 拆包}\\
0, & \text{否则}
\end{cases}
其中:
0 \le p < q \le m_r
为了保证每条 OD 流向形成一条完整、连续、唯一的建包路径,可以把每条路由看作一个 DAG,从第 0 个节点走到第 个节点:
\sum_{q>0} x_{r,0,q}=1
\sum_{p<k}x_{r,p,k}=\sum_{q>k}x_{r,k,q},\quad k=1,\ldots,m_r-1
\sum_{p<m_r}x_{r,p,m_r}=1
这样天然保证一条 OD 只会选择唯一的建包拆包路径。
混包与流向聚合
在分拣中心 ,若多个 OD 流向在 建包,并且它们下一跳相同、拆包点相同,则可以合并为一个集包流向组:
g=(i,j,k)
其中:
- :当前建包中心;
- :下一分拣中心;
- :下一拆包中心。
该组货量为:
Q_g=\sum_{r,p,q} \hat{y}_r x_{r,p,q}
需要满足:
v_{r,p}=i,\quad v_{r,p+1}=j,\quad v_{r,q}=k
这一步非常关键。
普通做法会把每个 OD 单独算成本,但优秀论文应该把相同集包规则下的流向聚合,这才符合“混包”的实际含义。
机器与人工选择
定义:
z_g^M=
\begin{cases}
1, & \text{集包组 } g \text{ 使用机器}\\
0, & \text{否则}
\end{cases}
z_g^H=
\begin{cases}
1, & \text{集包组 } g \text{ 使用人工}\\
0, & \text{否则}
\end{cases}
约束:
z_g^M+z_g^H=1
若机器每个格口最多处理 个包裹,则集包组 需要格口数:
b_g=\left\lceil \frac{Q_g}{a_i}\right\rceil
机器格口约束:
\sum_{g:i(g)=i} b_g z_g^M \le B_i
机器产能约束:
\sum_{g:i(g)=i} Q_g z_g^M \le C_i^M
人工最大流向数约束:
\sum_{g:i(g)=i} z_g^H \le L_i
人工产能约束:
\sum_{g:i(g)=i} Q_g z_g^H \le C_i^H
目标函数:
\min \sum_g \left(c_{i(g)}^M Q_g z_g^M+c_{i(g)}^H Q_g z_g^H\right)
如果题中成本是按“流向”“格口”或“包裹量”计价,应根据附件表 3 的字段调整。
问题 3:设备购置优化
第三问在第二问基础上增加设备决策。
假设设备类型集合为 ,每台设备有:
- 格口数
- 产能
- 购置成本
- 折旧年限
设场地 购买设备 的数量为:
n_{i,e}\in \mathbb{Z}_{\ge0}
未来一年货量增长 20%,若当前预测日货量为 ,则年化日均货量可取:
\hat y_r^{year}=1.2\hat y_r
或者若考虑逐月增长,可以用:
\hat y_{r,m}=\hat y_r(1+20\%)^{m/12}
设备折旧日成本:
d_e=\frac{K_e}{365Y_e}
设备格口约束变为:
\sum_g b_g z_g^M \le \sum_e B_e n_{i,e}
设备产能约束变为:
\sum_g Q_g z_g^M \le \sum_e C_e n_{i,e}
目标函数:
\min
\sum_{i,e}365d_e n_{i,e}
+
\sum_g 365c_{i(g)}^M Q_g z_g^M
+
\sum_g 365c_{i(g)}^H Q_g z_g^H
+
\text{人工兜底成本}
题目说明人工每人每天最多处理 5 个格口,每人每天工资 90 元。若机器不足,人工兜底人数为:
w_i=\left\lceil \frac{\sum_{g:i(g)=i} b_gz_g^H}{5}\right\rceil
人工工资成本:
90\times365\sum_i w_i
三、A 题 Python 代码框架
# A题:物流网络预测 + 集包规则 + 设备优化
# 依赖:pandas, numpy, lightgbm, sklearn, ortools
# pip install pandas numpy scikit-learn lightgbm ortools openpyxl
import pandas as pd
import numpy as np
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import TimeSeriesSplit
from lightgbm import LGBMRegressor
from ortools.sat.python import cp_model
import math
# ======================
# 1. 读取数据
# ======================
route_df = pd.read_excel("附件表1_走货路由.xlsx")
hist_df = pd.read_excel("附件表2_历史货量.xlsx")
site_df = pd.read_excel("附件表3_场地成本产能.xlsx")
device_df = pd.read_excel("附件表4_设备信息.xlsx")
# 假设 hist_df 字段:
# origin, dest, date, volume
hist_df["date"] = pd.to_datetime(hist_df["date"])
hist_df = hist_df.sort_values(["origin", "dest", "date"])
# ======================
# 2. 特征工程
# ======================
def make_features(df):
df = df.copy()
df["dow"] = df["date"].dt.dayofweek
df["month"] = df["date"].dt.month
df["day"] = df["date"].dt.day
df["is_weekend"] = (df["dow"] >= 5).astype(int)
df["od"] = df["origin"].astype(str) + "_" + df["dest"].astype(str)
for lag in [1, 2, 3, 7, 14, 28]:
df[f"lag_{lag}"] = df.groupby("od")["volume"].shift(lag)
for win in [7, 14, 28]:
df[f"roll_mean_{win}"] = (
df.groupby("od")["volume"]
.shift(1)
.rolling(win)
.mean()
.reset_index(level=0, drop=True)
)
df[f"roll_std_{win}"] = (
df.groupby("od")["volume"]
.shift(1)
.rolling(win)
.std()
.reset_index(level=0, drop=True)
)
return df
feat_df = make_features(hist_df)
feat_df = feat_df.dropna()
features = [
"dow", "month", "day", "is_weekend",
"lag_1", "lag_2", "lag_3", "lag_7", "lag_14", "lag_28",
"roll_mean_7", "roll_std_7",
"roll_mean_14", "roll_std_14",
"roll_mean_28", "roll_std_28"
]
# 类别变量编码
feat_df["origin_code"] = feat_df["origin"].astype("category").cat.codes
feat_df["dest_code"] = feat_df["dest"].astype("category").cat.codes
features += ["origin_code", "dest_code"]
# ======================
# 3. 训练预测模型
# ======================
train = feat_df.copy()
X = train[features]
y = train["volume"]
model = LGBMRegressor(
n_estimators=800,
learning_rate=0.03,
max_depth=-1,
num_leaves=64,
subsample=0.85,
colsample_bytree=0.85,
random_state=2026
)
model.fit(X, y)
# ======================
# 4. 递推预测未来7天
# ======================
def forecast_7_days(hist_df, model, features):
all_pred = []
work_df = hist_df.copy()
last_date = work_df["date"].max()
for h in range(1, 8):
pred_date = last_date + pd.Timedelta(days=h)
ods = work_df[["origin", "dest"]].drop_duplicates()
future = ods.copy()
future["date"] = pred_date
future["volume"] = np.nan
tmp = pd.concat([work_df, future], ignore_index=True)
tmp = tmp.sort_values(["origin", "dest", "date"])
tmp = make_features(tmp)
pred_rows = tmp[tmp["date"] == pred_date].copy()
pred_rows["origin_code"] = pred_rows["origin"].astype("category").cat.codes
pred_rows["dest_code"] = pred_rows["dest"].astype("category").cat.codes
pred_rows[features] = pred_rows[features].fillna(0)
pred = model.predict(pred_rows[features])
pred = np.maximum(pred, 0)
pred_rows["pred_volume"] = np.round(pred).astype(int)
all_pred.append(pred_rows[["origin", "dest", "date", "pred_volume"]])
append_df = pred_rows[["origin", "dest", "date"]].copy()
append_df["volume"] = pred_rows["pred_volume"].values
work_df = pd.concat([work_df, append_df], ignore_index=True)
return pd.concat(all_pred, ignore_index=True)
pred_df = forecast_7_days(hist_df, model, features)
pred_df.to_excel("结果表1_未来7天货量预测.xlsx", index=False)
# ======================
# 5. 构建路由字典
# ======================
# 假设 route_df 字段:origin, dest, route
# route 形如 "A-B-C-D"
def parse_route(s):
return str(s).split("-")
route_dict = {}
for _, row in route_df.iterrows():
key = (row["origin"], row["dest"])
route_dict[key] = parse_route(row["route"])
# 取未来7天总量或日均量作为优化输入
flow_df = pred_df.groupby(["origin", "dest"])["pred_volume"].sum().reset_index()
flow = {
(row["origin"], row["dest"]): int(row["pred_volume"])
for _, row in flow_df.iterrows()
}
# ======================
# 6. 集包规则优化:CP-SAT示意
# ======================
def optimize_bagging(route_dict, flow, site_df, scale=100):
"""
说明:
CP-SAT只能处理整数,因此成本可乘scale转整数。
该框架展示核心结构,实际需要按附件字段改列名。
"""
model = cp_model.CpModel()
# site参数
site_param = {}
for _, row in site_df.iterrows():
site = row["site"]
site_param[site] = {
"machine_cost": int(row["machine_cost"] * scale),
"human_cost": int(row["human_cost"] * scale),
"machine_capacity": int(row["machine_capacity"]),
"human_capacity": int(row["human_capacity"]),
"port_num": int(row["port_num"]),
"a": int(row["a"])
}
# x变量:OD在p建包,q拆包
x = {}
for od, path in route_dict.items():
m = len(path) - 1
for p in range(m):
for q in range(p + 1, m + 1):
x[(od, p, q)] = model.NewBoolVar(f"x_{od}_{p}_{q}")
# 每条OD形成连续路径
for od, path in route_dict.items():
m = len(path) - 1
# 起点流出
model.Add(sum(x[(od, 0, q)] for q in range(1, m + 1)) == 1)
# 中间节点流守恒
for k in range(1, m):
inflow = sum(x[(od, p, k)] for p in range(0, k))
outflow = sum(x[(od, k, q)] for q in range(k + 1, m + 1))
model.Add(inflow == outflow)
# 终点流入
model.Add(sum(x[(od, p, m)] for p in range(0, m)) == 1)
# 聚合集包组 g=(i,next_node,unpack_node)
groups = {}
for od, path in route_dict.items():
q_od = int(flow.get(od, 0))
if q_od == 0:
continue
m = len(path) - 1
for p in range(m):
for q in range(p + 1, m + 1):
i = path[p]
nxt = path[p + 1]
unpack = path[q]
g = (i, nxt, unpack)
groups.setdefault(g, [])
groups[g].append((od, p, q, q_od))
# 组是否启用、机器/人工
use_g, machine_g, human_g, volume_g, port_g = {}, {}, {}, {}, {}
max_volume = max(sum(flow.values()), 1)
for g, items in groups.items():
i = g[0]
use_g[g] = model.NewBoolVar(f"use_{g}")
machine_g[g] = model.NewBoolVar(f"machine_{g}")
human_g[g] = model.NewBoolVar(f"human_{g}")
volume_g[g] = model.NewIntVar(0, max_volume, f"vol_{g}")
# volume_g = sum flow_od * x
model.Add(
volume_g[g] == sum(q_od * x[(od, p, q)] for od, p, q, q_od in items)
)
# 如果volume>0则use=1;这里用弱连接,实际可加更严格big-M
model.Add(volume_g[g] <= max_volume * use_g[g])
model.Add(machine_g[g] + human_g[g] == use_g[g])
a_i = max(site_param[i]["a"], 1)
max_port = math.ceil(max_volume / a_i)
port_g[g] = model.NewIntVar(0, max_port, f"port_{g}")
# port >= volume/a
model.Add(port_g[g] * a_i >= volume_g[g])
model.Add(port_g[g] <= max_port * use_g[g])
# 场地资源约束
for site, param in site_param.items():
gs = [g for g in groups if g[0] == site]
if not gs:
continue
# 机器格口
model.Add(
sum(port_g[g] * machine_g[g] for g in gs) <= param["port_num"]
)
# 机器产能
model.Add(
sum(volume_g[g] * machine_g[g] for g in gs) <= param["machine_capacity"]
)
# 人工产能
model.Add(
sum(volume_g[g] * human_g[g] for g in gs) <= param["human_capacity"]
)
# 目标函数
obj_terms = []
for g in groups:
i = g[0]
cm = site_param[i]["machine_cost"]
ch = site_param[i]["human_cost"]
obj_terms.append(cm * volume_g[g] * machine_g[g])
obj_terms.append(ch * volume_g[g] * human_g[g])
model.Minimize(sum(obj_terms))
solver = cp_model.CpSolver()
solver.parameters.max_time_in_seconds = 600
solver.parameters.num_search_workers = 8
status = solver.Solve(model)
result = []
if status in [cp_model.OPTIMAL, cp_model.FEASIBLE]:
for g in groups:
if solver.Value(use_g[g]) == 1:
result.append({
"build_site": g[0],
"next_site": g[1],
"unpack_site": g[2],
"volume": solver.Value(volume_g[g]),
"ports": solver.Value(port_g[g]),
"method": "machine" if solver.Value(machine_g[g]) == 1 else "human"
})
return pd.DataFrame(result)
bag_result = optimize_bagging(route_dict, flow, site_df)
bag_result.to_excel("结果表2_集包规则.xlsx", index=False)
# ======================
# 7. 设备购置优化框架
# ======================
def optimize_devices(bag_result, site_df, device_df, growth=1.2):
"""
简化版:先根据第二问集包结果估算各场地需求,
再用整数规划选择设备组合。
"""
demand = bag_result.copy()
demand["future_volume"] = demand["volume"] * growth
site_need = demand.groupby("build_site").agg({
"future_volume": "sum",
"ports": "sum"
}).reset_index()
model = cp_model.CpModel()
n = {}
max_devices = 50
for _, srow in site_need.iterrows():
site = srow["build_site"]
for _, drow in device_df.iterrows():
dev = drow["device_type"]
n[(site, dev)] = model.NewIntVar(0, max_devices, f"n_{site}_{dev}")
total_cost = []
for _, srow in site_need.iterrows():
site = srow["build_site"]
need_port = int(math.ceil(srow["ports"]))
need_cap = int(math.ceil(srow["future_volume"]))
port_sum = []
cap_sum = []
for _, drow in device_df.iterrows():
dev = drow["device_type"]
port_sum.append(int(drow["port_num"]) * n[(site, dev)])
cap_sum.append(int(drow["capacity"]) * n[(site, dev)])
annual_cost = int(drow["cost"] / max(drow["depreciation_years"], 1))
total_cost.append(annual_cost * n[(site, dev)])
model.Add(sum(port_sum) >= need_port)
model.Add(sum(cap_sum) >= need_cap)
model.Minimize(sum(total_cost))
solver = cp_model.CpSolver()
solver.parameters.max_time_in_seconds = 300
solver.parameters.num_search_workers = 8
status = solver.Solve(model)
rows = []
if status in [cp_model.OPTIMAL, cp_model.FEASIBLE]:
for key, var in n.items():
val = solver.Value(var)
if val > 0:
rows.append({
"site": key[0],
"device_type": key[1],
"quantity": val
})
return pd.DataFrame(rows)
device_result = optimize_devices(bag_result, site_df, device_df)
device_result.to_excel("结果表3_设备购置方案.xlsx", index=False)
B 题:自助量贩餐厅菜量需求预测与运营优化设计
一、问题重述
B 题是典型的餐饮经营数据建模问题。
题目要求基于餐厅流水数据、每次消费菜品及营养成分数据,完成:
- 历史交易数据预处理、统计和可视化;
- 预测 2025 年 5 月工作日的就餐人数、营养素需求量、销售总额;
- 给出 2025 年 5 月 6 日至 5 月 12 日工作日午餐、晚餐备菜方案;
- 设计 10 元、15 元、20 元套餐;
- 给出经营优化建议。
二、B 题建模路线
问题 1:数据预处理与关联分析
预处理步骤:
- 删除重复订单;
- 处理缺失菜品、异常价格、异常营养值;
- 将交易流水表和菜品营养表按订单号合并;
- 构造订单级、菜品级、日级、餐段级数据。
核心统计:
| 分析对象 | 指标 |
|---|---|
| 菜品销量 | 均值、中位数、标准差、长尾分布 |
| 销售额 | 日销售额、午晚餐销售额 |
| 就餐人数 | 工作日/周末、午餐/晚餐 |
| 营养素 | 蛋白质、脂肪、碳水、热量等 |
| 关联关系 | 菜品共现、Apriori 关联规则、菜品相关系数 |
菜品销量通常满足长尾分布:少数高频菜贡献大部分销量。
可用帕累托图证明:
\frac{\sum_{i=1}^{k} sales_i}{\sum_{i=1}^{n} sales_i}
问题 2:需求预测模型
预测对象:
N_t:每日就餐人数
R_t:每日销售总额
M_{k,t}:第k类营养素需求量
推荐模型:
- 日级总量:LightGBM / XGBoost;
- 稳定营养素:SARIMA / 指数平滑;
- 多目标统一预测:多输出随机森林或 LightGBM 分目标训练。
特征:
| 特征 | 说明 |
|---|---|
| 日期 | 星期、月份、是否工作日 |
| 滞后 | lag1、lag7、lag14 |
| 滚动 | 7日均值、14日均值 |
| 餐段 | 午餐、晚餐 |
| 价格结构 | 客单价、菜品均价 |
| 菜品结构 | 热销菜占比、荤素比例 |
预测可靠性讨论:
- 使用时间序列交叉验证;
- 用 MAE、RMSE、MAPE 评价;
- 画真实值与预测值对比;
- 对节假日、极端天气、促销活动说明模型局限性。
问题 3:备菜优化模型
设:
q_{d,m,t}
表示第 天、第 餐段,菜品 的备菜份数。
预测需求为:
\hat{s}_{d,m,t}
目标是最大化利润,或最小化缺货与浪费综合损失:
\min
\sum_{d,m,t}
\left[
c_d^w(q_{d,m,t}-\hat{s}_{d,m,t})_+
+
c_d^o(\hat{s}_{d,m,t}-q_{d,m,t})_+
\right]
其中:
- :剩菜浪费成本;
- :缺货机会损失。
加入安全库存:
q_{d,m,t}\ge \hat{s}_{d,m,t}+z_{\alpha}\sigma_{d,m}
营养约束:
L_k \le \sum_d q_{d,m,t} a_{d,k} \le U_k
菜品多样性约束:
\sum_d I(q_{d,m,t}>0) \ge D_{\min}
荤素比例约束:
\rho_{\min}
\le
\frac{\sum_{d\in Meat}q_{d,m,t}}{\sum_d q_{d,m,t}}
\le
\rho_{\max}
消费习惯约束:
高频菜品必须保留:
q_{d,m,t}\ge Q_d^{min},\quad d\in Hot
问题 4:套餐设计模型
套餐价位为:
P\in\{10,15,20\}
设套餐是否包含菜品 :
x_d\in\{0,1\}
套餐成本:
\sum_d cost_d x_d \le \eta P
其中 是成本率上限,例如 0.55—0.70。
营养均衡目标:
\min \sum_k w_k
\left(
\frac{\sum_d a_{d,k}x_d-T_k}{T_k}
\right)^2
消费偏好收益:
\max \sum_d pref_d x_d
综合目标:
\max
\alpha \sum_d pref_dx_d
-
\beta \sum_k w_k
\left(
\frac{\sum_d a_{d,k}x_d-T_k}{T_k}
\right)^2
-
\gamma \left|\sum_d price_dx_d-P\right|
约束:
\sum_d price_dx_d \le P
n_{\min}\le \sum_d x_d\le n_{\max}
\sum_{d\in staple}x_d\ge1
\sum_{d\in protein}x_d\ge1
\sum_{d\in vegetable}x_d\ge1
三、B 题 Python 代码框架
# B题:餐厅需求预测 + 备菜优化 + 套餐设计
# pip install pandas numpy scikit-learn lightgbm mlxtend pulp openpyxl matplotlib
import pandas as pd
import numpy as np
from lightgbm import LGBMRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error
from mlxtend.frequent_patterns import apriori, association_rules
import pulp
import matplotlib.pyplot as plt
# ======================
# 1. 数据读取
# ======================
orders = pd.read_excel("附件1_餐厅流水.xlsx")
items = pd.read_excel("附件2_菜品营养.xlsx")
# 假设字段:
# orders: order_id, time, amount, customer_id
# items: order_id, dish, price, cost, calories, protein, fat, carb, category
orders["time"] = pd.to_datetime(orders["time"])
orders["date"] = orders["time"].dt.date
orders["hour"] = orders["time"].dt.hour
orders["meal"] = np.where(orders["hour"] < 15, "lunch", "dinner")
data = items.merge(
orders[["order_id", "time", "date", "meal", "amount", "customer_id"]],
on="order_id",
how="left"
)
# ======================
# 2. 统计分析
# ======================
dish_sales = data.groupby("dish").agg(
sales_qty=("dish", "count"),
sales_amount=("price", "sum"),
avg_price=("price", "mean")
).reset_index().sort_values("sales_qty", ascending=False)
dish_sales.to_excel("B_菜品销量统计.xlsx", index=False)
# 菜品共现矩阵
basket = pd.crosstab(data["order_id"], data["dish"])
basket = basket.applymap(lambda x: 1 if x > 0 else 0)
freq = apriori(basket, min_support=0.02, use_colnames=True)
rules = association_rules(freq, metric="lift", min_threshold=1.1)
rules.to_excel("B_菜品关联规则.xlsx", index=False)
# ======================
# 3. 构造日级预测数据
# ======================
daily = orders.groupby("date").agg(
people=("customer_id", "nunique"),
sales=("amount", "sum"),
orders=("order_id", "nunique")
).reset_index()
nut_daily = data.groupby("date").agg(
calories=("calories", "sum"),
protein=("protein", "sum"),
fat=("fat", "sum"),
carb=("carb", "sum")
).reset_index()
daily = daily.merge(nut_daily, on="date", how="left")
daily["date"] = pd.to_datetime(daily["date"])
daily = daily.sort_values("date")
def make_ts_features(df, target):
out = df.copy()
out["dow"] = out["date"].dt.dayofweek
out["month"] = out["date"].dt.month
out["day"] = out["date"].dt.day
out["is_workday"] = (out["dow"] < 5).astype(int)
for lag in [1, 2, 3, 7, 14]:
out[f"{target}_lag_{lag}"] = out[target].shift(lag)
for win in [7, 14]:
out[f"{target}_roll_mean_{win}"] = out[target].shift(1).rolling(win).mean()
out[f"{target}_roll_std_{win}"] = out[target].shift(1).rolling(win).std()
return out
def train_forecast(df, target, future_dates):
feat_df = make_ts_features(df, target).dropna()
feature_cols = [c for c in feat_df.columns if c not in ["date", target]]
model = LGBMRegressor(
n_estimators=500,
learning_rate=0.03,
num_leaves=31,
random_state=2026
)
model.fit(feat_df[feature_cols], feat_df[target])
work = df.copy()
preds = []
for d in future_dates:
new = pd.DataFrame({"date": [pd.to_datetime(d)], target: [np.nan]})
tmp = pd.concat([work[["date", target]], new], ignore_index=True)
tmp = make_ts_features(tmp, target)
row = tmp[tmp["date"] == pd.to_datetime(d)].copy()
row = row.fillna(0)
pred = max(0, model.predict(row[feature_cols])[0])
preds.append({"date": d, target: pred})
append = pd.DataFrame({"date": [pd.to_datetime(d)], target: [pred]})
work = pd.concat([work[["date", target]], append], ignore_index=True)
return pd.DataFrame(preds)
future_dates = pd.bdate_range("2025-05-01", "2025-05-31")
targets = ["people", "sales", "calories", "protein", "fat", "carb"]
pred_list = []
for target in targets:
pred = train_forecast(daily[["date", target]].dropna(), target, future_dates)
pred_list.append(pred.rename(columns={target: f"pred_{target}"}))
pred_result = pred_list[0]
for p in pred_list[1:]:
pred_result = pred_result.merge(p, on="date")
pred_result.to_excel("B_2025年5月工作日预测结果.xlsx", index=False)
# ======================
# 4. 备菜优化
# ======================
# 菜品日餐段需求预测:简单用历史均值比例分配
dish_meal = data.groupby(["date", "meal", "dish"]).size().reset_index(name="qty")
dish_profile = dish_meal.groupby(["meal", "dish"])["qty"].mean().reset_index()
dish_info = data.groupby("dish").agg(
price=("price", "mean"),
cost=("cost", "mean"),
calories=("calories", "mean"),
protein=("protein", "mean"),
fat=("fat", "mean"),
carb=("carb", "mean"),
category=("category", "first")
).reset_index()
def optimize_menu_for_day(meal, total_people, dish_profile, dish_info):
dishes = dish_info["dish"].tolist()
prob = pulp.LpProblem("menu_optimization", pulp.LpMinimize)
q = {
d: pulp.LpVariable(f"q_{d}", lowBound=0, cat="Integer")
for d in dishes
}
shortage = {
d: pulp.LpVariable(f"short_{d}", lowBound=0)
for d in dishes
}
waste = {
d: pulp.LpVariable(f"waste_{d}", lowBound=0)
for d in dishes
}
# 需求估计
prof = dish_profile[dish_profile["meal"] == meal].copy()
total_avg = prof["qty"].sum()
demand = {}
for _, row in prof.iterrows():
demand[row["dish"]] = row["qty"] / total_avg * total_people if total_avg > 0 else 0
for d in dishes:
dem = demand.get(d, 0)
prob += q[d] - dem == waste[d] - shortage[d]
# 目标:浪费 + 缺货
prob += pulp.lpSum([1.0 * waste[d] + 2.0 * shortage[d] for d in dishes])
# 多样性:至少20个菜有供应
y = {
d: pulp.LpVariable(f"y_{d}", lowBound=0, upBound=1, cat="Binary")
for d in dishes
}
M = 10000
for d in dishes:
prob += q[d] <= M * y[d]
prob += pulp.lpSum([y[d] for d in dishes]) >= min(20, len(dishes))
# 总份数接近人数 * 人均菜品数
prob += pulp.lpSum([q[d] for d in dishes]) >= total_people * 2
prob += pulp.lpSum([q[d] for d in dishes]) <= total_people * 5
prob.solve(pulp.PULP_CBC_CMD(msg=False))
rows = []
for d in dishes:
val = q[d].value()
if val and val > 0:
rows.append({"meal": meal, "dish": d, "quantity": round(val)})
return pd.DataFrame(rows)
plans = []
for d in pd.bdate_range("2025-05-06", "2025-05-12"):
people_pred = float(pred_result[pred_result["date"] == d]["pred_people"].iloc[0])
for meal in ["lunch", "dinner"]:
meal_people = people_pred * (0.55 if meal == "lunch" else 0.45)
plan = optimize_menu_for_day(meal, meal_people, dish_profile, dish_info)
plan["date"] = d
plans.append(plan)
menu_plan = pd.concat(plans, ignore_index=True)
menu_plan.to_excel("B_5月6日至12日备菜方案.xlsx", index=False)
# ======================
# 5. 套餐优化
# ======================
def optimize_package(price_limit, dish_info):
dishes = dish_info["dish"].tolist()
prob = pulp.LpProblem(f"package_{price_limit}", pulp.LpMaximize)
x = {
d: pulp.LpVariable(f"x_{d}", lowBound=0, upBound=1, cat="Binary")
for d in dishes
}
price = dict(zip(dish_info["dish"], dish_info["price"]))
cost = dict(zip(dish_info["dish"], dish_info["cost"]))
protein = dict(zip(dish_info["dish"], dish_info["protein"]))
calories = dict(zip(dish_info["dish"], dish_info["calories"]))
# 偏好用历史销量归一化
sales_pref = data.groupby("dish").size()
pref = {d: float(sales_pref.get(d, 0)) for d in dishes}
prob += pulp.lpSum([pref[d] * x[d] for d in dishes])
prob += pulp.lpSum([price[d] * x[d] for d in dishes]) <= price_limit
prob += pulp.lpSum([cost[d] * x[d] for d in dishes]) <= 0.65 * price_limit
prob += pulp.lpSum([x[d] for d in dishes]) >= 3
prob += pulp.lpSum([x[d] for d in dishes]) <= 6
# 营养下限,具体值需结合数据尺度调整
prob += pulp.lpSum([protein[d] * x[d] for d in dishes]) >= 10
prob += pulp.lpSum([calories[d] * x[d] for d in dishes]) >= 300
prob.solve(pulp.PULP_CBC_CMD(msg=False))
rows = []
for d in dishes:
if x[d].value() == 1:
rows.append({
"package_price": price_limit,
"dish": d,
"price": price[d],
"cost": cost[d],
"protein": protein[d],
"calories": calories[d]
})
return pd.DataFrame(rows)
packages = pd.concat([
optimize_package(10, dish_info),
optimize_package(15, dish_info),
optimize_package(20, dish_info)
], ignore_index=True)
packages.to_excel("B_套餐设计方案.xlsx", index=False)
C 题:谁是下一个“苏超”?
一、问题重述
C 题要求研究“省超”热度差异、相似性分类和潜力省份选择。
给定 15 个对象,包括苏超、齐鲁超赛、粤超、浙超、楚超、闽超、赣超、湘超、蒙超、疆超、渝超、川超、滇超、琼超、东北超等。需要构建多维指标体系,分析核心驱动力,找出与苏超最相似的 2—3 个省超,并在其他省份中找出最具举办潜力的 3 个。
二、C 题数据指标体系
建议构建五大一级指标:
| 一级指标 | 二级指标 |
|---|---|
| 赛事热度 | 现场观众、场均观众、直播观看量、短视频播放量、搜索指数 |
| 经济基础 | GDP、人均 GDP、居民消费支出、第三产业占比、文旅消费 |
| 人口与城市结构 | 常住人口、城镇化率、城市数量、城市间交通时间 |
| 足球文化 | 注册球员、足球场地数量、校园足球学校、职业俱乐部数量 |
| 传播能力 | 社交媒体指数、媒体报道量、短视频互动、地方文旅联动 |
苏超的成功,不只来自足球本身,而是“城市竞争叙事 + 低门槛群众体育 + 地方文旅营销 + 短视频传播 + 高密度城市网络”的叠加。公开报道显示,2025 苏超现场观众总数 243.3 万、线上直播观看 22.2 亿,是构建热度指数的重要标杆。
三、问题 1:省超热度指数模型
定义省超热度指数:
H_i=
w_1A_i+w_2B_i+w_3C_i+w_4D_i+w_5E_i
其中:
- :现场观赛指数;
- :线上传播指数;
- :城市参与指数;
- :商业转化指数;
- :社会话题指数。
对正向指标归一化:
x'_{ij}=\frac{x_{ij}-\min x_j}{\max x_j-\min x_j}
对负向指标归一化:
x'_{ij}=\frac{\max x_j-x_{ij}}{\max x_j-\min x_j}
权重建议用熵权法 + AHP 修正。
熵权法:
p_{ij}=\frac{x'_{ij}}{\sum_i x'_{ij}}
e_j=-\frac{1}{\ln n}\sum_i p_{ij}\ln p_{ij}
w_j=\frac{1-e_j}{\sum_j(1-e_j)}
四、问题 2:15 个省超相似性、聚类与苏超对标
对每个省超构建特征向量:
X_i=(x_{i1},x_{i2},\ldots,x_{ip})
先标准化,再使用:
- K-means 聚类;
- 层次聚类;
- PCA 降维可视化;
- 余弦相似度寻找与苏超最相似对象。
余弦相似度:
sim(i,JS)=
\frac{X_i\cdot X_{JS}}{\|X_i\|\|X_{JS}\|}
建议分类结果写成四类:
| 类型 | 特征 | 代表 |
|---|---|---|
| 强经济强传播型 | GDP 高、媒体强、城市密集 | 苏超、粤超、浙超 |
| 人口大省潜力型 | 人口多、消费强、联赛基础待提升 | 鲁、川、鄂、湘 |
| 文旅特色驱动型 | 地域文化强、旅游场景好 | 闽、赣、琼、滇 |
| 边疆特色参与型 | 地域跨度大、民族文化强 | 蒙、疆、东北超 |
与苏超最相似的候选一般会集中在:
浙江、广东、山东。
原因是它们经济体量、城市网络、媒体传播、消费能力和区域竞争叙事都较强。但最终要以你们采集数据后的余弦相似度/TOPSIS 排名为准。
五、问题 3:其他省份举办潜力评估
排除 15 个已有省超对象,对其他省份建立潜力指数:
P_i=
\alpha E_i+\beta Pop_i+\gamma T_i+\delta F_i+\theta M_i
其中:
- :经济消费潜力;
- :人口和城市规模;
- :交通与城市网络;
- :足球基础;
- :传播和文旅营销能力。
可用 TOPSIS 排名。
理想最优解:
A^+=\{\max z_{ij}\}
理想最劣解:
A^-=\{\min z_{ij}\}
距离:
D_i^+=\sqrt{\sum_j w_j(z_{ij}-A_j^+)^2}
D_i^-=\sqrt{\sum_j w_j(z_{ij}-A_j^-)^2}
贴近度:
C_i=\frac{D_i^-}{D_i^++D_i^-}
越高,举办潜力越大。
六、C 题 Python 代码框架
# C题:省超热度指数 + 聚类 + TOPSIS
# pip install pandas numpy scikit-learn matplotlib openpyxl
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.metrics.pairwise import cosine_similarity
import matplotlib.pyplot as plt
# ======================
# 1. 读取指标数据
# ======================
# 需要自己整理 province_super_data.xlsx
# 字段示例:
# name, province, audience_total, audience_avg, online_views,
# gdp, population, urbanization, football_fields,
# clubs, media_index, tourism_income, transport_density
df = pd.read_excel("C_省超指标数据.xlsx")
id_cols = ["name", "province"]
indicator_cols = [c for c in df.columns if c not in id_cols]
# ======================
# 2. 缺失值处理
# ======================
for c in indicator_cols:
df[c] = df[c].fillna(df[c].median())
# ======================
# 3. 归一化
# ======================
scaler = MinMaxScaler()
X_norm = scaler.fit_transform(df[indicator_cols])
X_norm = pd.DataFrame(X_norm, columns=indicator_cols)
# ======================
# 4. 熵权法
# ======================
def entropy_weight(X):
X = np.array(X, dtype=float)
X = X + 1e-12
P = X / X.sum(axis=0)
n = X.shape[0]
E = -np.sum(P * np.log(P), axis=0) / np.log(n)
D = 1 - E
W = D / D.sum()
return W
weights = entropy_weight(X_norm)
weight_df = pd.DataFrame({
"indicator": indicator_cols,
"weight": weights
}).sort_values("weight", ascending=False)
weight_df.to_excel("C_指标权重.xlsx", index=False)
# ======================
# 5. 热度指数
# ======================
df["heat_index"] = np.dot(X_norm, weights)
df_rank = df.sort_values("heat_index", ascending=False)
df_rank.to_excel("C_省超热度指数排名.xlsx", index=False)
# ======================
# 6. 聚类分析
# ======================
X_std = StandardScaler().fit_transform(df[indicator_cols])
# 可用肘部法选择K
sse = []
for k in range(2, 8):
km = KMeans(n_clusters=k, random_state=2026, n_init=20)
km.fit(X_std)
sse.append(km.inertia_)
# 假设选择4类
kmeans = KMeans(n_clusters=4, random_state=2026, n_init=20)
df["cluster"] = kmeans.fit_predict(X_std)
cluster_summary = df.groupby("cluster")[indicator_cols + ["heat_index"]].mean()
cluster_summary.to_excel("C_聚类特征描述.xlsx")
# PCA可视化
pca = PCA(n_components=2)
coord = pca.fit_transform(X_std)
df["pc1"] = coord[:, 0]
df["pc2"] = coord[:, 1]
plt.figure(figsize=(8, 6))
for c in sorted(df["cluster"].unique()):
sub = df[df["cluster"] == c]
plt.scatter(sub["pc1"], sub["pc2"], label=f"Cluster {c}")
for _, row in df.iterrows():
plt.text(row["pc1"], row["pc2"], row["name"], fontsize=8)
plt.legend()
plt.title("省超聚类PCA可视化")
plt.savefig("C_省超聚类PCA.png", dpi=300, bbox_inches="tight")
# ======================
# 7. 与苏超相似度
# ======================
names = df["name"].tolist()
js_idx = df.index[df["name"].str.contains("苏超")][0]
sim = cosine_similarity(X_std, X_std[js_idx].reshape(1, -1)).ravel()
df["similarity_to_suchao"] = sim
similar_rank = df[df.index != js_idx].sort_values(
"similarity_to_suchao", ascending=False
)
similar_rank[["name", "province", "similarity_to_suchao"]].head(5).to_excel(
"C_与苏超最相似省超.xlsx", index=False
)
# ======================
# 8. TOPSIS潜力评估
# ======================
# 对15个以外省份建立数据表
pot = pd.read_excel("C_其他省份潜力指标.xlsx")
pot_cols = [c for c in pot.columns if c not in ["province"]]
for c in pot_cols:
pot[c] = pot[c].fillna(pot[c].median())
Z = MinMaxScaler().fit_transform(pot[pot_cols])
W = entropy_weight(Z)
Z_weighted = Z * W
A_pos = Z_weighted.max(axis=0)
A_neg = Z_weighted.min(axis=0)
D_pos = np.sqrt(((Z_weighted - A_pos) ** 2).sum(axis=1))
D_neg = np.sqrt(((Z_weighted - A_neg) ** 2).sum(axis=1))
pot["potential_score"] = D_neg / (D_pos + D_neg)
pot_rank = pot.sort_values("potential_score", ascending=False)
pot_rank.to_excel("C_其他省份举办潜力排名.xlsx", index=False)
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)