1. 项目概述:从赛题到实战的完整复盘
去年带队参加“华为杯”数学建模竞赛,选的F题“飞行器质心平衡供油策略优化”至今记忆犹新。这道题本质上是一个典型的多约束动态优化问题,核心目标是在保证飞行器飞行姿态稳定的前提下,通过优化多个油箱之间的燃油调度策略,实现飞行航程的最大化或燃油消耗的最优化。听起来像是航空航天领域的专业问题,但其内核的优化思想、建模方法和求解技巧,在物流调度、生产排程、资源分配等众多工业场景中都有广泛应用。我们当时花了三天三夜,最终拿了个不错的奖项,过程中踩了不少坑,也积累了一些心得。今天就把这道题的解题思路、模型构建、算法实现以及那些“教科书上不会写”的实操细节,做一个完整的梳理和分享。无论你是正在备赛的研究生,还是对运筹优化、动态规划感兴趣的技术爱好者,相信这篇从实战中淬炼出的总结,都能给你带来直接的启发和可复现的代码参考。
2. 赛题核心与问题拆解:不只是数学题
2.1 问题背景与物理实质
题目描述了一个具有多个燃油箱的飞行器(例如大型客机或运输机)。飞行过程中,燃油不断被发动机消耗,导致全机重量减轻,更重要的是,燃油分布的改变会直接影响飞行器的质心位置。而质心(Center of Gravity, CG)的位置是飞行器静稳定性和操纵性的关键参数,必须被严格控制在某个安全范围内。如果质心过于靠前或靠后,轻则增加操纵难度和燃油消耗,重则危及飞行安全。
因此,供油策略不能简单地“哪个油箱近就用哪个”,而需要作为一个动态控制系统来设计:在满足发动机耗油需求的同时,通过在不同油箱间转移或选择消耗燃油,动态调整质量分布,使质心轨迹始终维持在理想区域内。这就像一边开着车,一边需要不断调整车上几个水桶的水量,让车的重心保持平衡,同时还要尽量让车跑得远。
2.2 核心难点与建模关键点
这道题的挑战在于多个耦合的约束和动态过程:
- 动态性:燃油消耗是一个连续时间过程,质心随之连续变化。我们需要做出的是一系列随时间变化的决策(何时从哪个油箱供油),而不是一个静态方案。
- 耦合约束:
- 质量守恒:总耗油率等于各油箱供油率之和。
- 质心约束:全机质心位置(与各油箱剩余油量及位置有关)需始终在允许的上下限内。
- 油箱容量与初始油量:每个油箱有最大容量,且初始油量可能不同。
- 供油能力限制:每个油箱可能有一个最大供油速率。
- 飞行器姿态平衡:有时还需考虑左右油箱对称消耗以防止滚转。
- 优化目标:通常是最大化航程(在给定总油量下)或最小化完成某段航程的油耗。这往往等价于在飞行全程,让飞机保持一个总体更优的气动构型(通常与质心位置有关)。
将上述物理问题转化为数学优化模型,是解题的第一步,也是决定后续求解难易的关键。
2.3 主流建模思路选型分析
我们当时调研并尝试了三种主流建模思路,各有优劣:
思路一:连续时间最优控制模型这是最“正统”也最复杂的思路。将各油箱油量作为状态变量,供油率作为控制变量,质心位置作为输出,建立状态空间方程。目标函数是积分形式的航程指标。然后使用庞特里亚金最小值原理或动态规划求解。
- 优点:理论严谨,能获得全局最优的连续时间解。
- 缺点:求解极其困难,特别是对于多油箱、非线性约束的情况,解析解几乎不可能,数值求解(如打靶法)对初值敏感,调试成本高,在数模竞赛的有限时间内风险极大。
- 我们的判断:此路不通,果断放弃。
思路二:离散时间动态规划将整个飞行时间离散化为若干个阶段(如每分钟或每消耗一定燃油为一个阶段)。在每个阶段,根据当前各油箱油量(状态),决定下一阶段的供油策略(决策),使阶段代价最小,并满足质心约束。最终从后向前递推或从前向后迭代寻找最优路径。
- 优点:能处理复杂约束,理论上是求全局最优解。
- 缺点:“维数灾难”。假设有3个油箱,每个油箱油量离散化为100个等级,那么状态空间就有100^3=100万个。计算量和存储需求爆炸,对于稍长的航程或更精细的离散,无法求解。
- 我们的判断:直接动态规划不可行,但它的思想可以借鉴。
思路三:基于时间/事件离散的混合整数规划或非线性规划这是我们最终采用的,也是实践中最可行的思路。其核心是“先离散,后优化”。
- 决策变量离散化:我们不求解连续的供油率函数,而是将飞行过程按固定时间间隔(如Δt=5分钟)或固定耗油事件(如每消耗总油量的1%)划分为N个时段。假设在每个时段内,供油策略是恒定的(例如,时段k内,只从某1个或某几个油箱以固定比例供油)。
- 模型转化:这样,连续控制问题转化为一个有限维参数优化问题。决策变量变成了每个时段各油箱的供油率或供油量比例。约束转化为每个时段初/末的质心计算不等式。
- 模型建立:目标函数(如总航程)和约束(质心上下限)都可以写成这些决策变量的函数,通常是非线性的(因为质心计算是油量的加权平均)。于是问题变成一个非线性规划问题。如果引入“是否从某油箱供油”的0-1变量,则成为更复杂的混合整数非线性规划,但精度可能更高。
- 求解:利用现代优化求解器(如MATLAB的
fmincon, Python的SciPy.optimize或更专业的IPOPT、Gurobi(针对MILP线性化后))进行求解。
注意:离散的粒度(Δt或事件间隔)是精度和计算量的权衡。Δt越小,越接近连续解,但变量越多,求解越慢。需要根据赛题数据规模进行测试。
3. 我们的模型构建与实现细节
3.1 模型假设与符号定义
在具体建模前,必须明确假设,这能简化问题并体现思考过程:
- 飞行条件恒定:假设在优化考虑的航段内,飞机飞行高度、速度、空气密度等保持不变。这样,单位油耗产生的航程变化可以简化为与飞机总重相关的一个函数(通常航程与重量对数成正比)。
- 燃油密度恒定:忽略温度导致的燃油密度变化。
- 油箱几何形状规则:假设每个油箱的质心位置在其几何中心,且不随油量变化而移动(对于大型翼箱,这可能不严格成立,但作为简化模型可接受)。
- 供油切换瞬时完成:忽略燃油管路切换带来的短暂延迟。
关键符号定义:
n: 油箱数量T: 总飞行时间(或待优化)N: 离散时段数Δt: 离散时段长度,T = N * Δtm_i^0: 油箱i的初始油量 (kg)(x_i, y_i, z_i): 油箱i的质心坐标 (m) (在机体坐标系下)m_{total}(t): 飞机总质量(空机质量 + 剩余燃油总质量)随时间变化r_i^k: 在第k个时段,从油箱i的供油率 (kg/s) ——这是核心决策变量CG_{min}, CG_{max}: 允许的质心位置范围(可能是x方向的前后限,或包含y方向的左右限)SFC: 发动机的燃油消耗率特性,可能为常数或与状态相关。
3.2 非线性规划模型建立
我们最终建立了如下模型:
决策变量:一个n x N的矩阵R,其中元素r_i^k表示第k时段从油箱i的供油率。此外,总时间T也可能作为变量(如果目标是最大航程)。
目标函数(最大化航程): 航程Range可以通过积分燃油消耗与距离的关系得到。在恒定飞行条件下,一个常用的简化模型是Breguet航程公式的变体:航程与初始总重和最终总重的比值的对数成正比。最大化航程等价于最大化这个比值,或者等价于在给定航程下最小化油耗。我们采用后者作为目标,因为约束更直观。Minimize J = sum_{k=1}^{N} (sum_{i=1}^{n} r_i^k) * Δt(总油耗) 实际上,在总油量固定时,最小化油耗等价于最大化利用燃油的效率,这与保持有利质心相关。更精细的目标可以设为:Minimize ∫ (Drag) dt,阻力与质心有关,但过于复杂。我们采用了一个等效目标:最小化全程质心偏离理想位置(如中点)的加权平方和。因为保持理想质心通常意味着更小的配平阻力和更高的气动效率,从而间接实现航程最优。这个目标函数是连续可导的,易于优化。Minimize J = sum_{k=1}^{N} [ (CG_x(k) - CG_{ideal})^2 ] * w_k其中CG_x(k)是第k时段末的质心x坐标,w_k是权重(可设为1)。
约束条件:
- 质量守恒/燃油消耗:每个时段的总供油率等于该时段发动机的需求耗油率
d_k(由飞行状态决定,可作为已知输入)。sum_{i=1}^{n} r_i^k = d_k, for k = 1...N - 油箱油量动态:
m_i^{k} = m_i^{k-1} - r_i^{k} * Δt, for i=1...n, k=1...Nm_i^{0}已知,m_i^{k} >= 0(油量非负) - 质心计算: 飞机总质心坐标是各部件质心的加权平均。假设空机质心
(x_empty, y_empty, z_empty)和重量m_empty已知。CG_x(k) = [ m_empty * x_empty + sum_{i=1}^{n} (m_i^{k} * x_i) ] / [ m_empty + sum_{i=1}^{n} m_i^{k} ]CG_y(k)同理。 - 质心约束:
CG_{min, x} <= CG_x(k) <= CG_{max, x}, for k = 1...N(如果考虑横向平衡,则对CG_y也有类似约束) - 供油率上下限:
0 <= r_i^k <= r_i^{max}(每个油箱最大供油能力) - 油箱容量约束(通常已由初始油量和非负约束隐含):
m_i^{k} <= Capacity_i
3.3 模型求解:从理论到代码
我们将上述NLP问题在Python中实现并求解。核心工具是SciPy.optimize.minimize函数。
步骤1:问题初始化与参数设置
import numpy as np from scipy.optimize import minimize, Bounds, LinearConstraint, NonlinearConstraint # ========== 参数设置 ========== n_tanks = 3 # 油箱数量 N_stages = 60 # 将飞行时间离散为60个阶段(例如,假设总时间3000秒,每阶段50秒) dt = 50.0 # 每个阶段时长 (秒) # 油箱属性 [初始油量(kg), x坐标(m), y坐标(m), 最大供油率(kg/s)] tanks = np.array([ [5000, 10.0, -5.0, 0.5], # 油箱1: 左翼 [5000, 10.0, 5.0, 0.5], # 油箱2: 右翼 [8000, 0.0, 0.0, 0.8] # 油箱3: 中央油箱 ]) # 飞机空机属性 m_empty = 40000 # 空机质量 (kg) cg_empty = np.array([8.0, 0.0]) # 空机质心坐标 (x, y) # 质心允许范围 cg_x_min, cg_x_max = 7.5, 8.5 # x方向前后限 cg_y_min, cg_y_max = -0.2, 0.2 # y方向左右限(对称平衡) # 发动机阶段耗油率 (kg/s), 这里假设为常数,实际可根据飞行计划变化 d_rate = 0.8 # 总需求耗油率 # ========== 决策变量向量化 ========== # 决策变量: 一个 (n_tanks * N_stages) 的一维数组 # 排列方式: [r_1^1, r_2^1, r_3^1, r_1^2, r_2^2, r_3^2, ..., r_1^N, r_2^N, r_3^N] num_vars = n_tanks * N_stages x0 = np.ones(num_vars) * (d_rate / n_tanks) # 初始猜测:平均分配步骤2:定义约束函数约束分为线性约束(质量守恒)和非线性约束(质心范围)。
# 1. 线性约束:每个阶段,各油箱供油率之和等于总需求d_rate A_eq = np.zeros((N_stages, num_vars)) for k in range(N_stages): A_eq[k, k*n_tanks:(k+1)*n_tanks] = 1.0 linear_constraint = LinearConstraint(A_eq, lb=d_rate, ub=d_rate) # 等式约束 # 2. 供油率上下限约束 bounds = Bounds(lb=np.zeros(num_vars), ub=np.tile(tanks[:, 3], N_stages)) # 每个油箱的供油率上限重复N次 # 3. 非线性约束:质心约束 def cg_constraint(x): """ 计算每个阶段末的质心,并返回与上下限的差值。 返回一个数组,前N_stages个是CG_x的下界差值,接着是上界差值... """ # 将决策变量重塑为 (N_stages, n_tanks) 矩阵 R = x.reshape((N_stages, n_tanks)) # 计算每个阶段末的油量 m_tanks = tanks[:, 0].copy() # 初始油量 cg_x_vals = np.zeros(N_stages) cg_y_vals = np.zeros(N_stages) for k in range(N_stages): # 更新本阶段油量消耗 m_tanks -= R[k, :] * dt # 计算总质量和总力矩 total_mass = m_empty + np.sum(m_tanks) moment_x = m_empty * cg_empty[0] + np.sum(m_tanks * tanks[:, 1]) moment_y = m_empty * cg_empty[1] + np.sum(m_tanks * tanks[:, 2]) # 计算质心 cg_x_vals[k] = moment_x / total_mass cg_y_vals[k] = moment_y / total_mass # 约束形式: g(x) >= 0 # 对于下界: CG_x - cg_x_min >= 0 -> g1 = cg_x_vals - cg_x_min # 对于上界: cg_x_max - CG_x >= 0 -> g2 = cg_x_max - cg_x_vals g_x_lower = cg_x_vals - cg_x_min g_x_upper = cg_x_max - cg_x_vals g_y_lower = cg_y_vals - cg_y_min g_y_upper = cg_y_max - cg_y_vals # 合并所有约束 return np.concatenate([g_x_lower, g_x_upper, g_y_lower, g_y_upper]) # 非线性约束:要求cg_constraint返回的所有值 >= 0 nonlinear_constraint = NonlinearConstraint(cg_constraint, lb=0, ub=np.inf)步骤3:定义目标函数我们采用最小化质心偏离理想位置的平方和。
def objective_function(x): """ 目标:最小化全程质心偏离理想位置(8.0, 0.0)的加权平方和。 """ R = x.reshape((N_stages, n_tanks)) m_tanks = tanks[:, 0].copy() total_cost = 0.0 cg_ideal_x = 8.0 # 理想质心x cg_ideal_y = 0.0 # 理想质心y for k in range(N_stages): m_tanks -= R[k, :] * dt total_mass = m_empty + np.sum(m_tanks) moment_x = m_empty * cg_empty[0] + np.sum(m_tanks * tanks[:, 1]) moment_y = m_empty * cg_empty[1] + np.sum(m_tanks * tanks[:, 2]) cg_x = moment_x / total_mass cg_y = moment_y / total_mass # 计算偏离代价,可以给x方向更高权重 cost = 1.0 * (cg_x - cg_ideal_x)**2 + 0.5 * (cg_y - cg_ideal_y)**2 total_cost += cost return total_cost步骤4:调用求解器并处理结果
# 使用SLSQP算法,它能处理边界约束和等式、不等式约束 result = minimize(objective_function, x0, method='SLSQP', bounds=bounds, constraints=[linear_constraint, nonlinear_constraint], options={'maxiter': 1000, 'ftol': 1e-6, 'disp': True}) if result.success: print("优化成功!") R_opt = result.x.reshape((N_stages, n_tanks)) # 计算并输出最终质心轨迹、剩余油量等 # ... (后文详细分析) else: print("优化失败:", result.message)4. 求解策略、技巧与结果分析
4.1 求解器选择与调参经验
直接使用上述模型求解,可能会遇到问题:变量多(3*60=180个),非线性约束复杂,容易陷入局部最优或收敛慢。
我们的调优策略:
分步优化(序列线性化/二次规划):这是关键技巧。先求解一个线性化的简化模型,将其结果作为NLP的初始值。
- 第一步:线性规划(LP)求可行解。我们将质心约束在每个时段线性近似。因为质心是油量的有理函数,可以在初始点(如平均供油)进行一阶泰勒展开,得到一个关于供油率
r_i^k的线性不等式。然后求解一个以“满足所有约束”为首要目标的LP(目标函数可以设为供油率变化平缓)。SciPy的linprog或PuLP库可以完成。这个LP解通常是一个可行的、但不一定最优的供油计划,它为NLP提供了一个极好的“热启动”点,远超平均分配的初始猜测。
- 第一步:线性规划(LP)求可行解。我们将质心约束在每个时段线性近似。因为质心是油量的有理函数,可以在初始点(如平均供油)进行一阶泰勒展开,得到一个关于供油率
变量缩放:供油率变量
r_i^k的数量级(如0.几)和目标函数、约束的数量级可能差异很大,影响求解器数值稳定性。我们对决策变量进行了归一化处理,将所有供油率除以d_rate,使其大致在0~1范围内。约束容差调整:质心约束的容差
tol不要设得太小(如1e-8),对于工程问题,1e-4或1e-3(米级)通常足够。过小的容差会增加不必要的求解难度。使用更强大的求解器:对于更大规模的问题,我们后来尝试了
IPOPT(通过cyipopt接口)和Gurobi(如果模型能转化为混合整数二次规划MIQP)。IPOPT处理大规模NLP能力很强。Gurobi则需要我们将模型线性化或二次化,并可能需要将连续供油率离散化为几个档位(如0%, 50%, 100%最大供油率),引入0-1整数变量,转化为MILP/MIQP问题,虽然会损失一些精度,但能保证找到全局最优解(对于线性/二次模型)。
4.2 结果可视化与策略解读
优化完成后,对结果的分析至关重要。我们绘制了以下几类图:
各油箱油量随时间变化曲线:可以清晰看到优化策略是如何调度燃油的。例如,可能优先消耗中央油箱的油以快速调整质心,然后交叉消耗左右翼箱以保持横向平衡。
import matplotlib.pyplot as plt # 计算油量变化 m_history = np.zeros((N_stages+1, n_tanks)) m_history[0, :] = tanks[:, 0] for k in range(N_stages): m_history[k+1, :] = m_history[k, :] - R_opt[k, :] * dt plt.figure(figsize=(10,6)) for i in range(n_tanks): plt.plot(np.arange(N_stages+1)*dt, m_history[:, i], label=f'Tank {i+1}') plt.xlabel('Time (s)') plt.ylabel('Fuel Mass (kg)') plt.legend() plt.grid(True) plt.title('Fuel Mass in Each Tank vs. Time') plt.show()飞机质心轨迹图:将计算出的每个阶段末的
CG_x,CG_y绘制出来,并标出允许的边界框。这是检验约束是否满足的最直观方式。理想的优化结果应该是质心轨迹平滑地穿过允许区域,并尽可能靠近理想线。供油率分配堆叠图:展示每个时刻,总耗油需求是如何由各油箱分担的。这能看出策略是“顺序供油”还是“并行供油”。
典型优化策略解读: 从我们多次求解的结果来看,一个常见的最优模式是:
- 初期:主要消耗中央油箱的燃油。因为中央油箱通常位于机身,其油量变化对质心纵向(x方向)影响显著。快速消耗中央油箱的油,可以使质心从初始位置(可能偏前或偏后)快速移动到理想区域中部。
- 中期:当中央油箱油量较低时,开始按一定比例同时消耗左右翼箱。此时需要精细控制左右翼箱的消耗比例,以维持横向(y方向)平衡。优化算法往往会给出一个非对称但周期性的左右切换策略,以将质心“锁”在理想点附近。
- 末期:所有油箱油量均较低,优化算法会更频繁地调整供油源,以应对油量少时质心对供油变化更敏感的特性。
4.3 灵敏度分析与模型稳健性
一个好的模型不仅要给出解,还要知道这个解有多“可靠”。我们做了简单的灵敏度分析:
- 离散粒度敏感性:将
Δt从50秒增大到100秒,或减小到25秒,重新求解。观察最优目标函数值的变化。如果变化很小(<1%),说明当前离散精度足够。如果变化大,则需要更细的离散。 - 参数扰动分析:将空机质心
cg_empty、油箱坐标等参数在小范围内随机扰动(例如±2%),重新求解多次。统计质心约束的违反情况(蒙特卡洛模拟)。这可以评估策略对模型误差的稳健性。一个稳健的策略应该在参数轻微变化时,依然能满足约束。 - 需求波动分析:实际飞行中,发动机耗油率
d_rate并非恒定。我们将d_rate设为随时间变化的序列(如爬升阶段高,巡航阶段平稳),重新优化。观察优化策略是否能自适应变化。通常,我们的模型框架能很好地处理这种变化,只需将d_k定义为随时间变化的输入即可。
5. 参赛实战心得与避坑指南
5.1 论文写作与建模表述
数模竞赛,结果和论文各占半边天。对于这道题,论文写作有几个关键点:
- 清晰的问题重述:不要照抄题目。要用自己的话,结合示意图,阐明“质心平衡”与“供油策略”、“航程”之间的物理和数学联系。
- 模型假设的合理性论证:每一条假设(如恒定飞行条件、油箱质心固定)都要说明其依据(“基于巡航段主要航程的考虑”、“简化分析,突出主要矛盾”),并讨论若放松该假设,模型将如何复杂化。
- 模型过渡的自然性:从物理模型(质心公式)到离散化决策,再到NLP模型,推导要连贯。给出决策变量、目标函数、约束条件的数学公式后,务必用一段文字解释其实际物理意义。
- 算法描述的层次性:不要直接贴代码。先讲清整体求解框架(离散化 -> NLP建模 -> 分步优化策略),再说明使用的工具(SciPy, IPOPT等)和关键算法(SLSQP内点法)。将核心的优化循环、约束处理逻辑用伪代码表示。
- 结果分析的深度:不要只说“我们得到了结果”。要分析结果为什么是合理的。结合前面的物理背景,解释优化策略背后的逻辑(如为什么先消耗中央油箱)。用图表说话,并对图表进行充分解读(“从图5可见,质心轨迹被严格控制在阴影区域内,且大部分时间贴近理想中线”)。
- 模型检验与推广:必须包含灵敏度分析部分,展示模型的稳健性。讨论模型的优点(综合考虑多约束、可扩展)和局限性(离散化误差、未考虑动态特性),并提出可能的改进方向(如结合反馈控制、更精细的燃油消耗模型)。
5.2 编程实现与调试坑点
- 变量重塑错误:决策变量从一维数组
x重塑为(N_stages, n_tanks)矩阵时,顺序非常重要(C顺序还是F顺序)。必须保证在目标函数和约束函数中,重塑方式一致。我们在这里栽过跟头,导致梯度计算错误,求解器无法收敛。建议:在代码中显式注释变量排列顺序,并编写一个小型测试函数验证重塑和计算的正确性。 - 约束违反的“软”处理:严格来说,质心约束必须每时每刻满足。但在数值求解中,有时在迭代初期或由于数值误差,会有轻微违反。如果求解器报告“约束不满足”,可以尝试:
- 略微放宽约束边界(如将
cg_x_min从7.5改为7.49),给求解器一点空间。 - 在目标函数中加入惩罚项。例如,将原目标改为
J + ρ * sum(max(0, cg_min - CG)^2 + max(0, CG - cg_max)^2),其中ρ是一个很大的惩罚系数。这可以将硬约束转化为软约束,有时更容易收敛,然后再用得到的结果作为初始值,去求解硬约束问题。
- 略微放宽约束边界(如将
- 求解器停滞与局部最优:SLSQP有时会陷入局部最优。我们的应对方法是:
- 多初始点尝试:除了平均分配初始值,还可以尝试其他启发式策略的初始值,例如“只从中央油箱开始供油”的策略。
- 调整求解器参数:增加
maxiter,减小ftol,或尝试其他方法如trust-constr。 - 简化问题:先求解一个更粗的离散化问题(N_stages较小),将其解插值作为精细问题的初始值。
- 代码效率:在约束函数中,避免使用循环计算每个阶段的油量和质心。虽然上面示例用了循环以便理解,但在实际比赛中,对于N很大的情况,应使用向量化操作。例如,可以预先计算好油量变化的累积和矩阵,一次性算出所有阶段的油量和质心,能大幅提升计算速度。
5.3 团队协作与时间管理
这道题工作量不小,三天时间非常紧张。
- 第一天上午:必须完成选题、彻底理解问题、确定基本建模路线(我们确定了离散化+NLP的路线)。同时,一人开始搜集资料(Breguet公式、飞机配平知识),一人开始搭建最基本的Python环境(安装SciPy, matplotlib等)和代码框架(定义参数、变量结构)。
- 第一天下午至晚上:集中火力推导数学模型,写出所有公式,并开始编写核心的目标函数和约束函数代码。完成第一个可运行的“版本”,即使结果不对。
- 第二天全天:调试代码,解决收敛性问题。实现结果的可视化。开始撰写论文的“问题分析”、“模型假设”、“模型建立”部分。切忌等代码完全调通再写论文。
- 第三天:优化求解策略(如加入分步优化),进行灵敏度分析,完善所有图表。全力撰写和润色论文,包括“结果分析”、“模型检验”、“优缺点讨论”。最后留出2-3小时做全文统稿、检查格式、生成最终PDF。
最重要的心得:保持沟通,每天至少开两次短会同步进度。将大问题分解为建模、编程、写作三个相对独立但又有交集的任务,让队友各司其职又紧密配合。遇到卡壳(如求解器不收敛)不要纠结超过2小时,及时团队讨论,切换思路。这道F题的魅力就在于,它没有唯一的标准答案,任何一个逻辑自洽、求解稳定、分析深入的模型,都能获得评委的青睐。