简介:本资源面向2025年电工杯数学建模竞赛参赛队伍及建模学习者,聚焦B题‘城市垃圾分类运输的路径优化与调度’这一现实痛点问题,提供从建模思路、算法实现到成果呈现的一站式解决方案。压缩包共含多类核心文件,包括Word格式无水印论文(含完整解题逻辑、多目标模型构建、GIS路径仿真与结果分析)、Python与MATLAB双版本可运行代码(覆盖数据清洗、车辆路径VRP建模、遗传/模拟退火算法求解及动态可视化)、结构化结果表格与原始/处理后数据集,整体大小为910.11MB。已有255人下载学习,适用于需快速掌握复杂物流调度建模流程、复现高分论文结构、理解多约束条件(如分类时效性、载重限制、时间窗)下路径协同优化机制的中高级建模者。所有代码模块化注释详尽,论文内容符合竞赛规范,支持直接提交或针对性修改,显著降低备赛门槛与试错成本。 拿到2025年电工杯B题的时候,我心里其实先松了一口气——"城市垃圾分类运输的路径优化与调度"这个题目,听起来很唬人,但本质上就是我们一直在练的车辆路径问题(VRP)换了一层场景外衣。真正让人头疼的不是建模本身,而是怎么把垃圾分类的行业约束翻译进数学模型,以及怎么在有限时间内跑出一套能自圆其说、有收敛趋势的算法结果。
这道题把三个子问题揉在了一起:垃圾产生量的数据处理、收运车辆的多路径规划、以及全局的车辆调度决策。三个子问题环环相扣,数据量大、约束杂、评价指标多,稍有遗漏就会整体跑偏。这篇文章我不打算讲那种"从零开始的建模教程",而是直接复盘我拿到题目之后,从拆题到建模、从算法到代码、从结果到论文的完整链路。中间会穿插大量我个人踩过的坑和觉得特别值得注意的细节,希望能给正在备赛或者打算参加建模竞赛的同学一个可复用的打法。
1. 拿到题目后,我先把"垃圾分类运输"翻译成了数学模型
1.1 本质是带容量约束和时间窗的VRP变种
垃圾分类运输,表面看是民生工程,但从优化角度说,它就是标准的车辆路径问题。赛题通常会给出一批垃圾收运点,每个点有坐标、有各类垃圾的产生量;给出处理厂(或中转站)的位置;给出车辆的数量、载重、工作时间等参数。要做的事就是:安排几辆车、各自去收哪些点、按什么顺序收,最后回到处理厂,使总成本最低,同时满足所有约束。
这个描述一出来,参加过建模的同学应该已经条件反射了——这就是经典的带容量约束的车辆路径问题(CVRP)。再加上我推测赛题里会包含收运时间窗口(比如厨余垃圾需要日产日清、有些小区只允许夜间收运),所以它又升级成了带时间窗的车辆路径问题(VRPTW)。如果再算上垃圾分成四五个品类,不同品类不能用同一辆车混装,那就是多车型、多品类的异质车队VRP。
别看题目包装得花里胡哨,把问题归到VRP家族之后,整个解题思路就清晰了一大半。后面所有的工作——数据预处理、模型构建、算法设计,都围绕"车辆-路径-时间窗-品类"这四个关键词展开。
1.2 子问题解耦:预测、规划、调度三个层面分开处理
这类题目,千万不要一上来就想建一个"全能模型"把所有东西同时优化。因为以竞赛的时间体量,同时优化所有层级的决策会让模型复杂度爆炸,算法根本收敛不动。
我的做法是把问题拆成三个层面:
- 第一层:垃圾量数据的处理与预测。如果赛题给了历史垃圾量时间序列,可能需要预测未来某一时段各收运点的垃圾产生量。如果只给了一个静态数值,那这层就简化为数据清洗和统计分析。
- 第二层:收运路径规划。已知每个点的垃圾量(或预测值)、车辆容量和各类约束,确定每辆车的访问顺序。这是整个题目的核心,也是算法最能拉开差距的地方。
- 第三层:车辆调度决策。在路径规划的基础上,决定每辆车几点出发、是否执行多趟任务,以及如何处理突发的新增需求。这一层在竞赛中可以适当简化,重点放在"能用约束说清楚"。
把问题解耦之后,每一层的目标就非常明确了。我在论文里的写法也是按这个逻辑递进的:先交代数据怎么处理,再建立路径优化模型,最后把调度规则作为一个扩展场景来讨论。评阅人看了也能一眼看出你的思路是清晰的。
1.3 赛题里最容易被忽略的隐藏约束
这类题目有个很坑的地方:很多约束不会直接写出来,而是藏在数据的编排方式里。比如:
- 不同垃圾品类是分开统计的,每个收运点某一类垃圾的产生量为0很正常,说明这个点不需要该类别的车去收;
- 处理厂可能有多个,而且不同处理厂只接收特定品类;
- 车辆工作时段是有限制的,比如早高峰时段不能上路;
- 有些收运点之间可能存在单向道路,导致距离矩阵不对称。
这些都是我在读题和翻数据时特别注意的地方。如果不做这一步,直接套标准CVRP模板,大概率会在细节上翻车。建议所有做这道题的同学,拿到数据后先花半天时间做探索性数据分析,把每一个字段的含义、取值范围、缺失情况都摸一遍,再做建模。
2. 数据坑位盘点:这题90%的坑都在数据理解上
2.1 坐标转换和距离计算矩阵
赛题给的位置信息,有的是经纬度,有的是平面坐标,有的甚至只给一个编号对应到地图上的点。这个处理直接决定整个算法的输入质量。
如果你拿到的是经纬度坐标,记得用Haversine公式计算球面距离,而不是简单套欧氏距离。尤其在城市尺度下,经纬度一度对应的地面距离在不同纬度差异很大,直接用欧氏距离算出来的路径完全不可信。我一般会写一个距离矩阵工具函数,输入点坐标列表,输出任意两点间的距离矩阵和行驶时间矩阵。如果赛题给了道路网络信息,那就要用最短路算法(比如Floyd或Dijkstra)先算出实际路网距离,再用这个距离矩阵作为后续算法的输入。
import numpy as np import math def haversine_dist(lon1, lat1, lon2, lat2): R = 6371.0 # 地球半径,单位km dlon = math.radians(lon2 - lon1) dlat = math.radians(lat2 - lat1) a = math.sin(dlat / 2) ** 2 + math.cos(math.radians(lat1)) * \ math.cos(math.radians(lat2)) * math.sin(dlon / 2) ** 2 return 2 * R * math.asin(math.sqrt(a)) def build_distance_matrix(points): n = len(points) dist_mat = np.zeros((n, n)) for i in range(n): for j in range(n): if i != j: dist_mat[i][j] = haversine_dist( points[i]['lon'], points[i]['lat'], points[j]['lon'], points[j]['lat'] ) return dist_mat这里有个小经验:车辆行驶时间不只是距离除以速度那么简单,城市工况下红灯、堵车会导致平均速度远低于道路限速。我在模型里给时间估算留了一个安全系数,比如平均车速取20-25km/h,并且设置一个固定的装卸服务时间参数(比如每点10分钟),这样算出来的总时间会更符合实际。
2.2 垃圾量数据的周期特征
如果赛题给了历史垃圾量数据,那处理的时候要充分考虑周期性。城市垃圾产量通常有明显的周内波动和节假日效应——周末厨余垃圾和生活垃圾往往比工作日多,节假日前后的可回收物也会冲高。这些规律在做预测和后续调度时非常关键。
我拿到这类数据后,第一件事不是急着建模,而是画时间序列图,按星期几分组看箱线图,看有没有明显异常值。如果有异常点,需要判断是记录错误还是真实的突发事件(比如大型活动后的垃圾量激增)。如果是记录错误,可以直接剔除或修正;如果是真实事件,把它作为特殊需求单独处理。
在此基础上,我会用一些相对简单但稳健的方法做预测——移动平均、指数平滑、或者小规模的时间序列回归。除非数据量特别大且有明显复杂的非线性模式,否则不建议在预测环节用太复杂的深度学习模型,因为竞赛时间有限,而且后面算法环节才是拿分重点。预测步骤只要能给出合理、可解释、误差可接受的数值就可以了。
2.3 数据的量级决定了算法的选择
赛题点数不同,解题策略完全不同。我遇到过几十个点的小规模数据和几百个点的大规模数据两种情况。点少的时候,可以用精确算法或者穷举思路做验证,算法性能不是瓶颈;点多的时候,必须上启发式算法,否则计算时间完全没法接受。
一个很实际的自测标准:如果收运点在50个以内,精确算法(比如分支定界或者Gurobi直接求解MILP模型)完全可以得到一个全局最优或近似最优解;如果超过100个点,直接上Gurobi很容易卡死,这时候就要把重心放在设计高效的元启发式算法上。我在做题前会根据数据量快速判断该走哪条路,避免在一开始就选错算法路线。
3. 模型构建:目标函数和约束条件的取舍策略
3.1 目标函数三层级设计
垃圾分类运输的优化目标,表面上是"总成本最低",但细拆起来其实是多层级的。我的做法是设置一个分层目标函数,不同层级的优先级不同:
- 第一优先级:使用的车辆数量最少。在车辆路径问题里,减少一辆车节省的固定成本(购车、司机、维护)通常远大于缩短行驶距离带来的可变成本节省。所以第一目标一定是尽量减少出车的台数。
- 第二优先级:总行驶距离最短。在车辆数固定的前提下,尽可能让所有车辆的总行驶里程最小,对应的是油耗、磨损、司机工时等可变成本。
- 第三优先级:各个车辆的负载均衡和时间均衡。这一点评阅人很看重,因为如果算法算出某一辆车干重活、另一辆车只收两个点就回来了,在实际场景中是不可用的方案。我会在目标函数里加一个均衡性的惩罚项,或者在算法的每一代评估中加一个负载均衡的指标。
在论文里,三个优先级可以写成加权求和的形式,也可以写成分层优化的形式。如果求加权和,注意权重系数要设置合理,否则会出现车辆数多但距离短的方案比车辆数少但距离长的方案得分更高的反直觉结果。我采用的是"先按车辆数排序,再按总距离排序"的字典序优化思路,更稳妥。
3.2 约束条件的合理取舍
模型里的约束条件不是越多越好,因为每加一个约束,求解难度都会上一个台阶。我在建模时把约束分成了三类:
第一类是硬性约束,违反就不可能执行。比如容量约束——任何一辆车装载的垃圾量不能超过车辆载重上限;时间窗约束——必须在规定的时间窗口内到达收运点;品类匹配约束——某类垃圾只能用对应的专用车辆运输;车辆路径闭合约束——车辆从处理厂出发,最终必须回到处理厂。
第二类是可以软化的约束,用一个惩罚项代替。比如时间窗可以设置一个软时间窗——允许迟到但是每迟到一分钟有一个惩罚成本,这样算法在搜索时更有弹性,避免因为个别点的约束太紧导致整个解不可行。实际项目中这是非常常用的手段。
第三类是可选的博弈性约束。比如"每辆车每天最多跑两趟"这类限制,如果写进模型会大大增加调度层面的复杂度。我在初版模型里一般不写死,而是在路径层解完之后再做可达性验证,如果确实需要车辆复用再单独扩展。
3.3 决策变量的表示方法
VRP类模型的决策变量通常是0-1变量:x_ijk表示车辆k是否从点i行驶到点j。这个变量在数学上很标准,但如果你用的是遗传算法等启发式方法,实际上并不需要显式定义这个变量——你只需要一个染色体编码来表示"每辆车的服务顺序",解码的时候就能自动得到对应的路径集合和总成本。我在代码里主要用的是基于路径的编码方式:用一串整数表示车辆访问的收运点顺序,用分隔符(比如0)区分不同车辆的任务段。这种编码方式直观、容易实现交叉变异,解码速度也快。
4. 主算法选型:为什么是"节约算法构造解 + 遗传算法加局部搜索"
4.1 精确算法的天花板
很多第一次做竞赛的同学会想着用Gurobi或者CPLEX直接求解MILP模型,但VRP是NP-hard问题,点一多就完全跑不动。即便只有50个点,完整的VRPTW模型的整数变量数量也会达到几千甚至上万,精确求解器可能要跑几小时甚至数天。竞赛只有三天时间,不可能靠精确算法拿结果。我的建议是:可以用Gurobi求解小规模算例来做结果验证和对比,但主算法一定得是启发式。
4.2 构造初始解:改进型节约算法(C-W算法)
好的启发式算法需要一个靠谱的初始解。如果初始解质量太差,后续的进化优化会花大量时间在"修复"而不是"改进"上。VRP里最经典的初始解构造方法是节约算法(Clarke-Wright Savings Algorithm),核心思想很直观:先给每个收运点单独派一辆车去服务,然后计算任意两个点合并到同一条路线时能节省的距离,按节约值从大到小排序,逐步合并路线,直到容量或时间窗约束不允许为止。
def clarke_wright_savings(dist_mat, demands, capacity): # 初始化:每个点单独一条路径 routes = [[i] for i in range(1, len(dist_mat))] # 计算节约值 savings = [] for i in range(1, len(dist_mat)): for j in range(i + 1, len(dist_mat)): saving = dist_mat[0][i] + dist_mat[0][j] - dist_mat[i][j] savings.append((saving, i, j)) savings.sort(reverse=True) # 按节约值从大到小合并路径,注意检查容量约束 ...在实际实现时,我不会完全按照经典C-W算法走,而是做两个改进:一是在合并时加入时间窗检查,如果合并后到达时间不满足任何一端的点的时间窗要求,就放弃这次合并;二是合并时尝试多个插入位置,不仅限于把两条路径的首尾相接,这样可以进一步压缩距离。
4.3 为什么用遗传算法而不是模拟退火或粒子群
VRP的搜索空间是离散且组合爆炸的,适合用群体智能算法。遗传算法、模拟退火、粒子群、蚁群都可以做。我个人更推荐遗传算法(GA),原因是它的并行性天然适合VRP这种多路径结构:种群中的每个个体就是一套完整的路径方案,交叉变异操作可以直接在编码层面操作路线片段,非常契合VRP的解结构。
当然,纯遗传算法也容易早熟收敛,所以我的方案是"遗传算法 + 局部搜索"的混合框架,也就是常说的Memetic Algorithm。每一代在所有个体完成交叉变异之后,对最优的几个个体做局部搜索强化——用2-opt(交换路径内两条边的连接方式)、Or-opt(移动路径中的一小段到其他位置)、Swap(交换两条路径中的两个点)这几个邻域算子反复搜索,直到没有改进为止。
4.4 参数设置的具体经验值
我这次用的参数范围可以分享给大家参考:
- 种群规模:100-200
- 交叉概率:0.8-0.9
- 变异概率:0.1-0.2
- 迭代代数:300-500
- 精英保留数:5-10
- 局部搜索频率:每代对最优的3-5个个体执行
这些参数不是拍脑袋定的。种群太小容易早熟,太大会拖慢每一代的计算速度;迭代代数太少还没收敛,太多则后期几乎没有改进,纯浪费计算资源。建议做一组小规模的参数敏感性测试,画出收敛曲线观察一下,再最终确定。
5. 代码实现:数据结构、算法流程与关键代码
5.1 数据结构设计
这道题的数据结构设计直接影响后续算法的开发效率。我用类的方式封装节点、车辆和路径,让代码更清晰,也方便后期扩展。
class Node: def __init__(self, node_id, category, amount, x, y, tw_min=0, tw_max=240): self.id = node_id self.category = category self.amount = amount self.x = x self.y = y self.tw_min = tw_min # 最早服务时间 self.tw_max = tw_max # 最晚服务时间 class Vehicle: def __init__(self, vehicle_id, capacity, category=0, fixed_cost=1.0): self.id = vehicle_id self.capacity = capacity self.category = category # 0表示通用,1/2/3/4表示对应品类 self.fixed_cost = fixed_cost class Route: def __init__(self, vehicle): self.vehicle = vehicle self.nodes = [0] # 从depot出发 self.load = 0 self.cost = 0 def add_node(self, node): self.nodes.append(node.id) self.load += node.amount self.cost += ... # 根据距离矩阵累加把每个点的时间窗作为Node的一部分有一个好处:后续做解码和时间窗校验时,直接遍历route.nodes查对应Node的属性即可,不需要额外维护复杂的映射表。这个设计在后面大量调试中帮我省了很多时间。
5.2 遗传算法的整体流程
完整算法流程我用一个框架表示:
- 读取并预处理数据,计算距离矩阵与行驶时间矩阵。
- 对每个垃圾品类分别构造初始路径集合(因为不同品类不能混装)。
- 将初始路径集合编码成染色体,初始化种群。
- 循环迭代:计算每个个体的适应度(总成本 + 惩罚项),执行锦标赛选择,执行交叉、变异,执行精英保留,对精英个体做局部搜索。
- 迭代结束后取最优个体,解码为路径方案。
- 后处理:计算各项指标(总车辆数、总距离、平均装载率、时间窗违反率),生成结果表。
5.3 遗传算子设计细节
编码方式我采用的是基于整数序列的自然数编码。比如有10个收运点、3辆车,一个染色体可以表示为[2, 5, 0, 1, 3, 6, 0, 4, 7, 8, 9],其中0是分隔符,代表车辆切换。但这里有个细节:不同品类的收运点混合编码会导致解码时出现某辆车拉错品类的错误。所以我给染色体加了一个"品类段"标记,确保每条路径段只包含同品类节点。
交叉算子我用的是顺序交叉(Order Crossover)和部分匹配交叉(PMX)两种交替使用。PMX适合处理有约束的路径段交换,顺序交叉则更擅长保留节点的相对顺序。变异算子则包括交换变异(随机交换两个基因位)、插入变异(把一个点插入到另一个位置)和逆转变异(反转一段子路径)。每次变异后要立即做容量和时间窗可行性校验,如果不可行就放弃这次变异,重新选一段尝试。
下面给一个交叉算子的简化示例,展示PMX的核心逻辑:
def pmx_crossover(p1, p2): size = len(p1) # 随机选择两个交叉点 start, end = sorted(random.sample(range(size), 2)) child = [-1] * size # 复制父本1的交叉区间 child[start:end+1] = p1[start:end+1] # 填充其余位置:先找父本2中不在child区间内的基因 for i in range(size): if child[i] == -1: candidate = p2[i] while candidate in child[start:end+1]: candidate = p2[p1.index(candidate)] child[i] = candidate return child这个实现的逻辑比较简洁,但要注意在真实代码里,编码里的0分隔符会干扰交叉操作,所以交叉前需要把0去掉、按路径段拼接,或者对分隔符做特殊处理。我处理的办法是分层编码:染色体只编码"每个车辆段的节点序列",车辆分配另用一个数组表示,这样交叉时车辆分配和节点顺序就能分开进化。
5.4 局部搜索的实现要点
局部搜索是提升解质量的关键。我用三个算子:
2-opt:在一条路径内部,选择两条不相交的边,断开后反向连接。这个算子在路径优化里极其经典,几乎适用于所有VRP变种。具体实现时,把路径看成一个环形结构,从depot出发又回到depot,所以需要对中间段做反转而不是简单交换两个点。
Or-opt:把一条路径中的连续1到3个点取出来,插入到这条路径或另一条路径的其他位置。这个操作对改善局部拥堵非常有效,实现起来也不复杂。
Swap:交换两条路径中的各一个点,或者一条路径内的两个点。适用于车辆间的负载均衡调整。
局部搜索的停止条件是"连续k次迭代没有改进",k我一般设为100。每次局部搜索后重新计算路径的容量和总成本,如果有改进就更新。
def two_opt(route, dist_mat): improved = True best_route = route[:] best_cost = compute_cost(route, dist_mat) while improved: improved = False for i in range(1, len(route) - 2): for j in range(i + 2, len(route)): new_route = route[:i] + route[i:j][::-1] + route[j:] new_cost = compute_cost(new_route, dist_mat) if new_cost < best_cost - 1e-9: best_route = new_route best_cost = new_cost improved = True route = best_route return best_route, best_cost在实际代码里还有个加速优化:不需要每次重新计算整条路径的成本,只需要计算断点附近的那几段边的变化量即可。但对竞赛规模的数据来说,全量重算是可以接受的,代码简洁优先。
6. 结果怎么呈现才能对得起你的努力
6.1 收敛曲线与分析
算法跑完,第一件事是画收敛曲线和路径图。收敛曲线要能证明你的算法是正常迭代的,而不是一开始就乱跳到末尾。具体来说,画出每一代的最优适应度和平均适应度两条曲线,最优适应度应该是单调下降或先快速下降后趋于平稳,平均适应度围绕最优值波动但整体也呈下降趋势。如果最优曲线在早期就完全不动了,说明算法大概率陷入了局部最优,就要考虑调整变异概率或者增加局部搜索力度。
路径图方面,我会画一个带坐标的地图散点图,用不同颜色区分不同车辆的路线,并标注depot和各收运点。这张图一定要画得清晰,因为评阅人大概率第一眼就看结果图,路径规划效果好不好一目了然。如果路径交叉严重,即便总距离指标不错,印象分也会打折扣。我的经验是:画图时把od的标记放大、路线线条加粗、图例注明车辆编号和车辆载重利用率,让每辆车跑的全貌一看就懂。
6.2 对比实验:你至少要做三组
竞赛评阅里,对比实验是拉开档次的关键。光说自己算法好是不够的,得在同一套数据上对比才行。我做了三组对比:
第一组:无算法调度(当前人工方案)vs 改进后优化方案。如果题目数据里给了类似现有方案的参考值,这组对比最直观,直接说明你的方法能省多少钱、少用多少车、少跑多少公里。如果题目没有给,可以用一个简单的"按距离最近邻贪心"构造的基线方案做对比,体现算法优化的必要性和效果。
第二组:单一算法 vs 你的改进算法。比如"纯遗传算法"和"GA+局部搜索"在相同迭代次数下的对比,重点展示混合算法在收敛速度和解的质量上的优势。
第三组:小规模精确解 vs 启发式解。如果收运点数较少,用Gurobi求出精确最优解,再和你的启发式结果对比,说明启发式算法取得的解和最优解的差距在可接受范围内(比如5%以内)。这组实验最有说服力,直接给评审一个量化感知:你的算法离最优解还有多远。
6.3 灵敏度分析怎么设计
灵敏度分析是很多同学容易忽略但特别加分的部分。我做了三组灵敏度分析:车辆载重变动(-20%、-10%、+10%、+20%)对总车辆数和总距离的影响;时间窗松紧程度(扩大或缩小20%)对可行性的影响;垃圾量预测误差(±10%)对方案鲁棒性的影响。这些分析一方面展示了对模型的深入理解,另一方面也回应了现实场景中参数波动的风险。
如果题目给了多个场景的数据(比如不同片区或不同季节的数据),还可以做多场景的对比分析,说明算法在不同规模、不同分布下的泛化能力。这是拿"创新点"分的好地方。
6.4 论文每部分的写作要点
摘要部分要四段式:第一段用两三句话说清楚背景和问题是什么;第二段写你建立了什么模型、用了什么方法;第三段给出核心结果,用数据说话;第四句轻轻一句点出方案的实践价值和可推广性。摘要里的数一定不能拍脑袋,要和正文结果表完全对应,评阅人会专门抽查。
问题分析和模型建立部分,重点写清楚"为什么这样建模"和"哪些假设是不合理的"。不要只罗列数学公式,要交代每一条约束的现实意义——比如"车辆装载量不能超过额定载重"对应的是车辆行驶安全。符号说明要全,公式编号要有序,这是细节分。
算法设计部分是评阅人重点看的段落。建议给每一个算法模块配上流程图或伪代码,伪代码的每一行都要和后面代码核心逻辑对应,这样审稿人读起来会非常顺。参数表要单独列出来,包括参数名称、含义、取值、调节依据。
结果部分要注意"图文并茂"。一张总结果对比表、一张路径可视化图、一张收敛曲线图,三个基础图必须有。好的论文在结果部分会很克制,每个数据都有明确的作用,不堆砌。
7. 给下一届选手的几条实在建议
代码规范这块,从第一天就按工程标准写。变量名别用a、b、c这种,文件夹按data、src、results、figures分好,结果输出统一用CSV保存。比赛的第三天晚上你可能要改十几次参数重跑几十组实验,如果代码一团乱,光debug就能耗掉你半天时间。
时间分配上,我的建议是:第一天上午快速读题和数据,下午完成数据预处理和基线模型;第二天全力做算法和实验,晚上开始写论文框架;第三天上午补全实验和分析,下午集中写完整论文、统一格式、校对摘要。千万不要花两天时间搭模型,最后只剩半天写论文——那样你再好的算法也白搭。
最后说一个我个人特别受益的习惯:做任何模型改动前,先把当前版本的结果完整备份好,并记录下来改了什么、效果如何。这样在论文讨论部分写"我们尝试了xxx方法,结果yyy"的时候,每一步都有真实依据,而不是靠回忆拼凑。建模竞赛比的从来不只是算法,它比的是谁在有限时间里更系统地解决问题。希望这篇复盘能帮你少走一些弯路,祝你比赛顺利。
本文还有配套的精品资源,点击获取