1996年高教社杯全国大学生数学建模竞赛 B 题:《节水洗衣机》真题解析与 MATLAB 解决方案
🏆 本文已收录于专栏:《滚雪球学数学建模(含历年真题)》
本专栏面向数学建模竞赛学习者,系统覆盖真题解析、建模方法、算法实现、论文写作与 AI 辅助建模等核心环节。无论是建模新手,还是备战华为杯、高教社杯、华数杯、国赛、美赛 MCM/ICM 的参赛者,都能在这里找到清晰、完整、可复用的建模思路,持续更新,长期有效。
🎯 免责声明: 本文题目来源于互联网公开内容,仅供学习交流与建模方法研究,不构成竞赛指导。请遵守相关赛事规则,独立完成竞赛作品,使用本文内容所产生的后果由使用者自行承担。
🎉 专栏限时优惠中:一次订阅,永久解锁,后续内容持续更新。 欢迎点击了解 👉 查看专栏详情 👈
全文目录:
1996B题:节水洗衣机
真题展示
如下为原(真)题,展示如下:
在开始之前,我想先说几句真心话:这道1996年的老题,放在今天依然非常值得深入研究。 它看起来是一个优化问题,但背后藏着资源分配、效果评价、多目标权衡等多个建模层次。很多同学拿到这类题后第一反应是"哦,这就是个最优化,用线性规划就行"——这恰恰是最常见的建模误区。
让我们系统地把它拆开来看。
一、前言:为什么这道题值得分析?
1996年的这道节水洗衣机题,是国赛历史上少数几道"同时考察物理机理建模 + 工程优化 + 实际评价"的综合性题目之一。它的特别之处在于:
第一,它有明确的物理过程。 洗衣机的"加水—漂洗—脱水"过程是可以被数学化描述的,涉及洗涤剂浓度随轮次的变化规律。这要求建模者不能只凭"直觉",而要真正理解洗涤物理机制。
第二,它有多个决策变量。 运行几轮?每轮加多少水?总用水量是约束还是目标?这些问题相互耦合,不能单独求解。
第三,它需要评价"洗涤效果"。 什么叫"满足一定洗涤效果"?这个"效果"如何量化?这是题目中最难、也最关键的一步——在没有明确定义的情况下,建模者需要自己构建合理的评价指标。
第四,它要求对比分析。 题目最后要求对照"目前常用洗衣机的运行情况"进行评价,这意味着你的模型不能闭门造车,需要有基准对比。
正因为如此,这道题是训练综合建模能力的绝佳素材。下面我们逐步展开。
二、题目背景与现实意义
2.1 现实背景
中国是一个淡水资源相对匮乏的国家,人均淡水占有量仅为世界平均水平的约四分之一。洗衣机在家庭日常用水中占据相当大的比例,传统全自动洗衣机每次洗衣用水量约为100至150升,而其中漂洗环节消耗的水量往往占总用水量的60%以上。
传统洗衣机的漂洗策略非常粗放:固定加满水、漂洗固定次数、每次完全排干。这种策略的最大问题在于:它没有根据洗涤剂残留浓度动态调整用水策略,导致大量的水被"低效使用"——前几次漂洗已经将大部分洗涤剂稀释,后几次漂洗几乎是在做无用功。
2.2 建模的现实意义
设计一个节水洗衣机控制程序,本质上是一个资源分配优化问题:在保证洗涤效果(洗涤剂残留浓度低于某阈值)的前提下,使总用水量最小化。
这道题的建模意义远不止于洗衣机本身:
- 它代表了一类"过程优化"问题的通用建模范式;
- 它涉及如何将工程约束转化为数学约束;
- 它考察如何在"效果"与"成本"之间寻找最优平衡;
- 它要求建模者既懂物理机制,又能写出可求解的数学模型。
三、题目重述
3.1 已知条件
根据题目图片,已知条件如下:
-
洗衣机运行过程:放入衣物和洗涤剂后,洗衣机按以下固定流程运行:
加水 → 漂洗 → 脱水 → 加水 → 漂洗 → 脱水 → ⋯ → 加水 → 漂洗 → 脱水 \text{加水} \to \text{漂洗} \to \text{脱水} \to \text{加水} \to \text{漂洗} \to \text{脱水} \to \cdots \to \text{加水} \to \text{漂洗} \to \text{脱水} 加水→漂洗→脱水→加水→漂洗→脱水→⋯→加水→漂洗→脱水
称一个"加水—漂洗—脱水"为运行一轮。
-
目标:在满足一定洗涤效果的条件下,使总用水量最少。
-
决策变量:运行多少轮( n n n),以及每轮加入多少水( v 1 , v 2 , … , v n v_1, v_2, \ldots, v_n v1,v2,…,vn)。
-
约束:需满足一定的洗涤效果(洗涤剂残留量低于某标准)。
3.2 待解决问题
题目要求解决以下核心问题:
问题一: 建立洗涤剂残留浓度随漂洗轮次变化的数学模型,描述洗涤过程的物理机制。
问题二: 在给定总用水量的条件下,如何分配各轮用水量,使漂洗效果最好(即最终残留浓度最低)?
问题三: 在满足一定洗涤效果标准的前提下,如何确定最优轮次数和各轮用水量,使总用水量最少?并与目前常用洗衣机的运行情况进行对比评价。
3.3 附件数据说明
本题未提供附件数据,属于纯机理建模题型。
这意味着:
- 所有参数(如衣物吸水量、初始洗涤剂量等)需要建模者合理假设;
- 模型的物理机制需要从第一性原理出发推导;
- 结果需要在参数合理范围内进行讨论,而非依赖特定数值。
给初学者的提示: 没有数据不代表无从下手。恰恰相反,纯机理建模题更考验你对问题本质的理解。很多同学看到"没有数据"就慌了,其实这类题目的关键是把物理过程写清楚,再从中提炼数学结构。
四、问题分析
4.1 问题一分析:浓度递推模型
核心问题: 每轮漂洗后,衣物中残留的洗涤剂浓度如何变化?
这是一个典型的浓度稀释问题,可以用递推关系来描述。
关键物理过程:
- 漂洗前:衣物中含有一定量的洗涤剂(溶于衣物吸附的水中);
- 加水:向洗衣桶中加入清水 v i v_i vi 升;
- 漂洗:洗涤剂在桶内均匀混合(这是一个关键假设);
- 脱水:甩干,衣物保留固定量的水(设为 w w w 升),其余水全部排出。
这个过程的数学本质是:每轮漂洗都是一次稀释操作,洗涤剂总量在衣物吸附水中被稀释。
4.2 问题二分析:固定总水量下的最优分配
核心问题: 给定 V t o t a l V_{total} Vtotal 升水,分成 n n n 轮,每轮用 v i v_i vi 升,如何使最终残留浓度最低?
这是一个约束优化问题:
min v 1 , v 2 , … , v n c n \min_{v_1, v_2, \ldots, v_n} c_n v1,v2,…,vnmincn
s.t. ∑ i = 1 n v i = V t o t a l , v i ≥ 0 \text{s.t.} \quad \sum_{i=1}^{n} v_i = V_{total}, \quad v_i \geq 0 s.t.i=1∑nvi=Vtotal,vi≥0
问题二有一个非常优美的数学结论:在总水量固定、轮数固定的条件下,每轮用水量相等时漂洗效果最优(均值不等式的直接应用)。
这个结论非常重要,它为工程实践提供了明确的指导建议。
4.3 问题三分析:最优轮次与用水量的联合优化
核心问题: 同时优化轮次 n n n 和各轮用水量 v i v_i vi,使总水量最小,同时满足洗涤效果约束。
这是问题二的逆问题,也是整道题的核心。注意:
- n n n 是整数变量(不能漂洗2.5轮);
- 增加轮次会增加固定用水量(每轮加水至少需要覆盖桶底);
- 每轮用水量有上下界约束(洗衣桶容量有限)。
4.4 各问题之间的逻辑关系
具体相关示意图绘制如下,仅供参考:
逻辑关系说明:
问题一是基础,它建立了整个模型的"核心方程"——浓度递推公式。没有这个公式,后面的优化无从谈起。问题二是在问题一的基础上求解一个有约束的最优化,并得出"等量分水"的结论。问题三将问题二的结论作为输入,进一步联合优化轮次变量。最后的对比分析则需要将模型结果与现实基准进行比较,体现建模的实用价值。
五、整体建模思路
5.1 建模路线
具体相关示意图绘制如下,仅供参考:
5.2 模型选择依据
| 模型 | 适用场景 | 本题理由 |
|---|---|---|
| 浓度递推模型(差分方程) | 离散过程的状态演化 | 漂洗是离散的轮次过程,状态是洗涤剂浓度 |
| 约束最优化模型 | 资源分配问题 | 总水量有限,需要最优分配 |
| 整数规划 | 决策变量含整数 | 轮次 n n n 必须是正整数 |
| 参数灵敏度分析 | 检验模型稳定性 | 参数(如吸水量 w w w)需要假设,需检验影响 |
5.3 算法实现思路
- 问题二:解析求解,利用均值不等式直接证明等量分水最优,无需数值计算。
- 问题三:数值枚举 + 解析计算。对每个轮次 n n n(从1到N_max),代入等量分水结论,计算满足约束所需的最小总水量,再取所有 n n n 中最小总水量对应的方案。
5.4 结果验证方法
- 物理合理性验证:浓度应单调递减,且趋近于零;
- 极端情况验证: n = 1 n=1 n=1 时结果退化为简单稀释;
- 对比验证:与传统固定策略(每轮满桶水,固定轮次)比较;
- 参数灵敏度验证:改变 w w w、初始浓度等参数,观察结果变化幅度。
六、数据预处理
本题无附件数据,所有参数均来自合理假设。但我们仍需对参数进行整理和说明,这相当于"参数化预处理"。
6.1 参数合理性来源
| 参数 | 符号 | 假设值 | 依据 |
|---|---|---|---|
| 衣物漂洗后吸附水量 | w w w | 10 升 | 5kg衣物约吸附2L/kg |
| 初始洗涤剂量 | m 0 m_0 m0 | 50 g | 常规洗衣粉用量 |
| 初始洗涤剂浓度 | c 0 c_0 c0 | m 0 / w m_0/w m0/w | 由定义计算 |
| 洗涤效果标准(残留率) | ϵ \epsilon ϵ | 0.02(2%) | 工程经验值 |
| 洗衣桶有效容量 | V m a x V_{max} Vmax | 40 升 | 家用洗衣机容量 |
| 每轮最少加水量 | v m i n v_{min} vmin | 5 升 | 确保桶内水能流动 |
6.2 参数敏感性预判
在没有真实数据的情况下,应预先判断哪些参数对结果影响最大:
- w w w(吸水量) 是最关键参数。它决定了每轮漂洗的稀释倍数,对最终结果有决定性影响。
- ϵ \epsilon ϵ(残留率阈值) 直接决定了需要多少轮漂洗。
- 初始洗涤剂量 m 0 m_0 m0 只影响绝对浓度,不影响最优分水策略(后面将看到这一点)。
6.3 MATLAB 参数初始化
%% data_preprocess.m
% 功能:初始化模型所需的所有物理参数
% 作者:建模示例代码
% 说明:本题无附件数据,所有参数为合理假设值
function params = data_preprocess()
% ====== 物理参数 ======
params.w = 10; % 衣物吸附水量(升),关键参数
params.m0 = 50; % 初始洗涤剂量(克)
params.c0 = params.m0 / params.w; % 初始浓度(克/升)
% ====== 约束参数 ======
params.epsilon = 0.02; % 允许的最大残留率(即最终残留量/初始量 <= epsilon)
params.V_max = 40; % 洗衣桶最大容量(升)
params.v_min = 5; % 每轮最少加水量(升)
params.n_max = 10; % 最大考虑轮次数
% ====== 传统洗衣机参数(用于对比)======
params.v_traditional = 40; % 传统洗衣机每轮加满水(升)
params.n_traditional = 3; % 传统洗衣机固定漂洗3轮
% ====== 验证参数合理性 ======
assert(params.w > 0, '吸水量必须为正数');
assert(params.epsilon > 0 && params.epsilon < 1, '残留率必须在(0,1)之间');
assert(params.V_max > params.v_min, '桶容量必须大于最小加水量');
fprintf('参数初始化完成:\n');
fprintf(' 初始浓度 c0 = %.2f 克/升\n', params.c0);
fprintf(' 残留率阈值 epsilon = %.2f%%\n', params.epsilon * 100);
fprintf(' 吸水量 w = %.1f 升\n', params.w);
end
代码解析:
这段代码将所有参数集中在一个函数中管理,有以下几个设计考量:
-
为什么要把参数单独写成函数? 因为后面的灵敏度分析需要反复修改参数,集中管理避免在多个文件中查找和修改,大大减少出错概率。
-
为什么用
params.w而不是直接用全局变量? 结构体传参比全局变量更安全,避免命名冲突,在大型项目中是标准做法。 -
assert语句的作用是什么? 在竞赛中,加入参数合理性检验可以帮助你在调试时快速定位问题,避免因为参数设置错误导致结果离谱而浪费时间。 -
初学者注意: 不要把 c 0 c_0 c0 和 m 0 m_0 m0 混淆。 m 0 m_0 m0 是洗涤剂的总量(克), c 0 c_0 c0 是浓度(克/升)。后面的递推方程用哪个要统一,不能混用。
七、模型假设
模型假设是数学建模论文中最容易写得"空洞"的部分。很多同学写"假设洗涤均匀进行"这样的废话,而没有说明为什么需要这个假设,以及违反这个假设会有什么影响。
下面是本题的完整假设列表,每条都附有说明:
假设1:漂洗过程中洗涤剂在桶内均匀混合。
数学含义: 每轮漂洗结束时,桶内溶液浓度处处相等。
为什么需要: 这是浓度递推公式成立的前提。如果不均匀,则脱水后衣物中残留的浓度就不等于桶内平均浓度,递推方程无法建立。
违反后果: 若实际混合不均匀,则模型会低估残留量。
假设2:每次脱水后,衣物中保留的水量恒为 w w w 升(与加水量无关)。
数学含义: 脱水后衣物吸附水量是固定常数。
为什么需要: 实际中脱水效果与转速、时间有关,但为了建立可解析的递推方程,需要这个简化。
违反后果: 若 w w w 随轮次变化,递推方程需修改为变系数形式。
假设3:每轮加入的水为清水(洗涤剂浓度为零)。
数学含义: 加水操作不引入新的洗涤剂。
为什么需要: 显然,漂洗阶段不应再加洗涤剂,这是物理常识的数学化。
假设4:衣物纤维不吸附洗涤剂(洗涤剂完全溶于水中)。
数学含义: 洗涤剂总量 = 浓度 × 水量,无其他吸附项。
为什么需要: 简化模型,避免引入复杂的吸附动力学。
违反后果: 若有吸附效应,实际残留量会高于模型预测值,即模型偏乐观。
假设5:洗衣机每轮的运行过程(漂洗时间、转速)相同,漂洗效率只取决于水量。
数学含义: 模型中不考虑时间维度,每轮效果完全由稀释倍数决定。
假设6:洗涤效果仅由最终漂洗结束后衣物中的洗涤剂残留率来衡量。
数学含义: 效果评价指标为 r n = m n / m 0 ≤ ϵ r_n = m_n / m_0 \leq \epsilon rn=mn/m0≤ϵ,其中 m n m_n mn 是第 n n n 轮后残留洗涤剂量。
八、符号说明
| 符号 | 单位 | 含义 |
|---|---|---|
| n n n | 无量纲(正整数) | 漂洗总轮次 |
| v i v_i vi | 升 | 第 i i i 轮加入的清水量 |
| V V V | 升 | 总用水量, V = ∑ i = 1 n v i V = \sum_{i=1}^{n} v_i V=∑i=1nvi |
| w w w | 升 | 每次脱水后衣物保留的水量(常数) |
| m 0 m_0 m0 | 克 | 初始洗涤剂总量 |
| m k m_k mk | 克 | 第 k k k 轮漂洗脱水后衣物中残留的洗涤剂量 |
| c k c_k ck | 克/升 | 第 k k k 轮漂洗过程中桶内溶液的浓度 |
| r k r_k rk | 无量纲 | 第 k k k 轮后的洗涤剂残留率, r k = m k / m 0 r_k = m_k / m_0 rk=mk/m0 |
| ϵ \epsilon ϵ | 无量纲 | 允许的最大残留率(洗涤效果标准) |
| V m a x V_{max} Vmax | 升 | 洗衣桶最大容量 |
| v m i n v_{min} vmin | 升 | 每轮最少加水量 |
| V ∗ V^* V∗ | 升 | 最优总用水量 |
| n ∗ n^* n∗ | 正整数 | 最优漂洗轮次 |
| v ∗ v^* v∗ | 升 | 最优每轮用水量(等量分水时) |
九、模型一:浓度递推基础模型
9.1 模型思想
这个模型要回答一个基本问题:每轮漂洗后,衣物中残留的洗涤剂有多少?
我们来还原物理过程:
- 漂洗前(第 k k k 轮开始前): 衣物中含有 m k − 1 m_{k-1} mk−1 克洗涤剂,溶于 w w w 升水中。
- 加水: 向桶中加入 v k v_k vk 升清水。此时桶中总水量为 w + v k w + v_k w+vk 升,洗涤剂总量仍为 m k − 1 m_{k-1} mk−1 克。
- 漂洗(均匀混合): 桶内浓度变为 c k = m k − 1 / ( w + v k ) c_k = m_{k-1} / (w + v_k) ck=mk−1/(w+vk)。
- 脱水: 排出桶中水,衣物保留 w w w 升水,携带洗涤剂 m k = c k ⋅ w = m k − 1 ⋅ w / ( w + v k ) m_k = c_k \cdot w = m_{k-1} \cdot w / (w + v_k) mk=ck⋅w=mk−1⋅w/(w+vk) 克。
9.2 数学表达式
递推方程:
m k = m k − 1 ⋅ w w + v k , k = 1 , 2 , … , n m_k = m_{k-1} \cdot \frac{w}{w + v_k}, \quad k = 1, 2, \ldots, n mk=mk−1⋅w+vkw,k=1,2,…,n
其中 m 0 m_0 m0 为初始洗涤剂量(已知), w w w 为衣物保留水量(常数), v k v_k vk 为第 k k k 轮加水量(决策变量)。
展开递推:
m n = m 0 ⋅ ∏ k = 1 n w w + v k m_n = m_0 \cdot \prod_{k=1}^{n} \frac{w}{w + v_k} mn=m0⋅k=1∏nw+vkw
残留率:
r n = m n m 0 = ∏ k = 1 n w w + v k r_n = \frac{m_n}{m_0} = \prod_{k=1}^{n} \frac{w}{w + v_k} rn=m0mn=k=1∏nw+vkw
这个公式非常重要。注意观察: r n r_n rn 与 m 0 m_0 m0 无关! 这意味着初始洗涤剂量不影响最优分水策略,只影响是否需要更多轮次(当然, m 0 m_0 m0 越大, c 0 c_0 c0 越高,但相对残留率的表达式中 m 0 m_0 m0 已经约掉了)。
洗涤效果约束:
r n = ∏ k = 1 n w w + v k ≤ ϵ r_n = \prod_{k=1}^{n} \frac{w}{w + v_k} \leq \epsilon rn=k=1∏nw+vkw≤ϵ
9.3 参数解释
- w / ( w + v k ) w/(w+v_k) w/(w+vk) 称为第 k k k 轮的稀释因子,范围在 ( 0 , 1 ) (0,1) (0,1) 之间,表示该轮漂洗后残留比例。
- 稀释因子越小( v k v_k vk 越大),该轮去除效果越好;
- n n n 轮的总残留率是各轮稀释因子的乘积。
9.4 求解方法
模型一本身是解析可解的,不需要数值方法。给定 v k v_k vk,直接代入公式计算即可。
9.5 MATLAB 实现
%% build_model.m
% 功能:计算给定各轮用水量下的洗涤剂残留情况
% 输入:params(参数结构体),v_vec(各轮用水量向量,单位:升)
% 输出:result(包含各轮残留量、残留率等信息的结构体)
function result = build_model(params, v_vec)
n = length(v_vec); % 漂洗轮次
w = params.w; % 衣物吸附水量
m0 = params.m0; % 初始洗涤剂量
% 初始化存储数组
m = zeros(1, n+1); % m(k+1) 对应第k轮后残留量(MATLAB从1开始)
r = zeros(1, n+1); % 残留率
c = zeros(1, n); % 各轮漂洗时桶内浓度
m(1) = m0; % 初始状态
r(1) = 1.0; % 初始残留率为100%
% 逐轮计算递推
for k = 1:n
% 检查加水量是否合理
if v_vec(k) < params.v_min
warning('第%d轮加水量%.2f升低于最小值%.2f升', k, v_vec(k), params.v_min);
end
if v_vec(k) > params.V_max
error('第%d轮加水量%.2f升超过桶容量%.2f升', k, v_vec(k), params.V_max);
end
% 漂洗时桶内浓度(混合后)
c(k) = m(k) / (w + v_vec(k));
% 脱水后残留洗涤剂量(核心递推公式)
m(k+1) = m(k) * w / (w + v_vec(k));
% 残留率
r(k+1) = m(k+1) / m0;
end
% 打包输出结果
result.m = m; % 各轮残留量(克)
result.r = r; % 各轮残留率
result.c = c; % 各轮漂洗浓度(克/升)
result.n = n; % 总轮次
result.V_total = sum(v_vec);% 总用水量(升)
result.v_vec = v_vec; % 各轮用水量
result.final_r = r(end); % 最终残留率(关键指标)
% 判断是否满足洗涤效果标准
result.is_satisfied = (result.final_r <= params.epsilon);
fprintf('\n=== 漂洗过程分析 ===\n');
fprintf('总轮次: %d轮\n', n);
fprintf('总用水量: %.2f 升\n', result.V_total);
fprintf('最终残留率: %.4f%%\n', result.final_r * 100);
fprintf('是否满足洗涤标准: %s\n', mat2str(result.is_satisfied));
end
代码解析:
-
核心递推
m(k+1) = m(k) * w / (w + v_vec(k))直接对应数学模型中的 m k = m k − 1 ⋅ w / ( w + v k ) m_k = m_{k-1} \cdot w/(w+v_k) mk=mk−1⋅w/(w+vk),一行代码对应一个公式,非常清晰。 -
为什么数组从1开始而不是从0开始? MATLAB的数组下标从1开始,所以
m(1)对应数学上的 m 0 m_0 m0,m(k+1)对应 m k m_k mk。这个偏移容易让初学者犯错,务必在注释中说明。 -
为什么要检查加水量? 竞赛中经常出现优化算法给出"离谱"的解(如负数用水量),加入检查可以快速发现问题。
-
result.is_satisfied的设计:将是否满足约束作为结果的一部分输出,方便后面的优化程序判断可行性。
9.6 结果分析
以传统洗衣机(每轮40升,共3轮)为例验证模型:
r 3 = ( 10 10 + 40 ) 3 = ( 1 5 ) 3 = 0.008 = 0.8 r_3 = \left(\frac{10}{10+40}\right)^3 = \left(\frac{1}{5}\right)^3 = 0.008 = 0.8% r3=(10+4010)3=(51)3=0.008=0.8
这个结果表明:传统洗衣机3轮后残留率约为0.8%,远低于我们设定的2%阈值——但它用了120升水!模型一的建立为我们接下来的优化奠定了定量基础。
十、模型二:固定总水量下的最优水量分配
10.1 基础模型的不足
模型一描述了"给定用水方案,计算漂洗结果",但没有回答"用水方案怎么定最优"。问题二要求:在总用水量 V V V 和轮次 n n n 固定的前提下,如何分配各轮用水量,使最终残留率最低?
10.2 改进思路:均值不等式的应用
优化问题形式:
min v 1 , … , v n ∏ k = 1 n w w + v k \min_{v_1, \ldots, v_n} \prod_{k=1}^{n} \frac{w}{w + v_k} v1,…,vnmink=1∏nw+vkw
s.t. ∑ k = 1 n v k = V , v k ≥ v m i n \text{s.t.} \quad \sum_{k=1}^{n} v_k = V, \quad v_k \geq v_{min} s.t.k=1∑nvk=V,vk≥vmin
注意:最小化 ∏ w w + v k \prod \frac{w}{w+v_k} ∏w+vkw 等价于最大化 ∏ ( w + v k ) \prod (w+v_k) ∏(w+vk)(因为分子是常数 w n w^n wn)。
定理(均值不等式): 对正数 x 1 , x 2 , … , x n x_1, x_2, \ldots, x_n x1,x2,…,xn,若 ∑ x k = C \sum x_k = C ∑xk=C(常数),则:
∏ k = 1 n x k ≤ ( C n ) n \prod_{k=1}^{n} x_k \leq \left(\frac{C}{n}\right)^n k=1∏nxk≤(nC)n
等号成立当且仅当 x 1 = x 2 = ⋯ = x n x_1 = x_2 = \cdots = x_n x1=x2=⋯=xn。
令 x k = w + v k x_k = w + v_k xk=w+vk,则 ∑ x k = n w + V \sum x_k = nw + V ∑xk=nw+V,由均值不等式:
∏ k = 1 n ( w + v k ) ≤ ( n w + V n ) n \prod_{k=1}^{n} (w + v_k) \leq \left(\frac{nw + V}{n}\right)^n k=1∏n(w+vk)≤(nnw+V)n
等号成立当且仅当 v 1 = v 2 = ⋯ = v n = V / n v_1 = v_2 = \cdots = v_n = V/n v1=v2=⋯=vn=V/n。
10.3 改进模型表达式
结论:在总用水量 V V V 和轮次 n n n 固定时,各轮平均分水( v i = V / n v_i = V/n vi=V/n)使最终残留率最低:
r n ∗ = ( w w + V / n ) n r_n^* = \left(\frac{w}{w + V/n}\right)^n rn∗=(w+V/nw)n
这是一个极其重要的解析结论,它将 n n n 维优化问题化简为了一维问题(只需要确定 n n n 和 V V V 的组合)。
从工程角度理解: "每轮用同样多的水"是最优策略,这与我们的直觉相符——如果某轮多用了水,另一轮少用了水,总效果反而不如平均分配。
10.4 MATLAB 实现
%% solve_model.m (模型二部分)
% 功能:在固定总水量V和轮次n下,计算最优残留率(等量分水)
% 并与不等量分配方案对比
function result2 = solve_model_fixed_V(params, V_total, n)
w = params.w;
% ====== 等量分水方案(最优)======
v_equal = V_total / n; % 每轮用水量相同
% 验证约束
if v_equal < params.v_min
warning('等量分水每轮%.2f升,低于最小值,请增加总水量或减少轮次', v_equal);
end
if v_equal > params.V_max
warning('等量分水每轮%.2f升,超过桶容量', v_equal);
end
% 最优残留率(解析公式)
r_optimal = (w / (w + v_equal))^n;
% ====== 不等量分水方案(对比用)======
% 示例:前多后少,不均匀分配
v_unequal = zeros(1, n);
v_unequal(1) = V_total * 0.5; % 第一轮用一半
for k = 2:n
v_unequal(k) = V_total * 0.5 / (n-1); % 其余均分另一半
end
% 计算不等量方案残留率
r_unequal = 1.0;
for k = 1:n
r_unequal = r_unequal * w / (w + v_unequal(k));
end
% ====== 输出结果 ======
result2.V_total = V_total;
result2.n = n;
result2.v_equal = v_equal;
result2.r_optimal = r_optimal;
result2.v_unequal = v_unequal;
result2.r_unequal = r_unequal;
result2.improvement = (r_unequal - r_optimal) / r_unequal * 100;
fprintf('\n=== 模型二:固定总水量下的最优分配 ===\n');
fprintf('总水量: %.1f升, 轮次: %d轮\n', V_total, n);
fprintf('等量分水:每轮%.2f升,残留率=%.4f%%\n', v_equal, r_optimal*100);
fprintf('不均分水:残留率=%.4f%%\n', r_unequal*100);
fprintf('等量分水改善效果: %.2f%%\n', result2.improvement);
end
代码解析:
-
为什么设计"不等量对比方案"? 仅仅给出"等量最优"的结论是不够的,需要用数值实验来展示"不等量有多差",这样才能让读者(和评委)信服。
-
improvement的计算: 这是一个非常好的习惯——计算改进幅度而不仅仅是绝对值,便于读者直观感受优化效果。 -
初学者注意: 上面的"不等量方案"是人为构造的,目的只是对比,不代表最优策略的竞争者。真正的最差策略(在约束范围内)需要更复杂的分析,但竞赛中通常不需要这么深入。
10.5 对比分析
以 w = 10 w=10 w=10L、 V = 40 V=40 V=40L、 n = 4 n=4 n=4 为例:
| 方案 | 各轮用水量 | 残留率 |
|---|---|---|
| 等量分水(最优) | 10, 10, 10, 10 升 | ( 10 / 20 ) 4 = 6.25 (10/20)^4 = 6.25% (10/20)4=6.25 |
| 前多后少 | 20, 6.7, 6.7, 6.7 升 | 约 7.8% |
| 前少后多 | 2.5, 2.5, 2.5, 32.5 升 | 约 9.1% |
等量分水明显优于其他策略,数值验证了理论结论。
十一、模型三:最优轮次与用水量的联合优化
11.1 综合建模目标
综合模型要解决的是:同时确定最优轮次 n ∗ n^* n∗ 和最优总用水量 V ∗ V^* V∗,使在满足洗涤效果约束的前提下总用水量最小。
这是整道题的核心模型。
11.2 模型结构
基于模型二的结论(各轮等量分水最优),我们可以将问题化简。
决策变量: 轮次 n n n(正整数),每轮用水量 v v v(实数,等量时所有轮次相同)。
目标函数:
min n , v V = n ⋅ v \min_{n, v} V = n \cdot v n,vminV=n⋅v
约束条件:
( w w + v ) n ≤ ϵ (洗涤效果约束) \left(\frac{w}{w + v}\right)^n \leq \epsilon \quad \text{(洗涤效果约束)} (w+vw)n≤ϵ(洗涤效果约束)
v m i n ≤ v ≤ V m a x (用水量约束) v_{min} \leq v \leq V_{max} \quad \text{(用水量约束)} vmin≤v≤Vmax(用水量约束)
n ∈ Z + , n ≤ n m a x (轮次约束) n \in \mathbb{Z}^+, \quad n \leq n_{max} \quad \text{(轮次约束)} n∈Z+,n≤nmax(轮次约束)
化简: 对于给定的 n n n,满足效果约束的最小 v v v 值为:
v m i n n e e d e d ( n ) = w ⋅ ( ϵ − 1 / n − 1 ) v_{min_needed}(n) = w \cdot \left(\epsilon^{-1/n} - 1\right) vminneeded(n)=w⋅(ϵ−1/n−1)
推导过程:
( w w + v ) n = ϵ \left(\frac{w}{w+v}\right)^n = \epsilon (w+vw)n=ϵ
w w + v = ϵ 1 / n \frac{w}{w+v} = \epsilon^{1/n} w+vw=ϵ1/n
v = w ( ϵ − 1 / n − 1 ) v = w\left(\epsilon^{-1/n} - 1\right) v=w(ϵ−1/n−1)
此时最小总用水量为:
V ∗ ( n ) = n ⋅ v m i n n e e d e d ( n ) = n ⋅ w ⋅ ( ϵ − 1 / n − 1 ) V^*(n) = n \cdot v_{min_needed}(n) = n \cdot w \cdot \left(\epsilon^{-1/n} - 1\right) V∗(n)=n⋅vminneeded(n)=n⋅w⋅(ϵ−1/n−1)
最优轮次:
n ∗ = arg min n ∈ 1 , 2 , … , n m a x V ∗ ( n ) n^* = \arg\min_{n \in {1, 2, \ldots, n_{max}}} V^*(n) n∗=argn∈1,2,…,nmaxminV∗(n)
约束条件: v m i n ≤ v m i n n e e d e d ( n ) ≤ V m a x v_{min} \leq v_{min_needed}(n) \leq V_{max} vmin≤vminneeded(n)≤Vmax。
11.3 求解流程
具体相关示意图绘制如下,仅供参考:
流程说明:
这个枚举流程非常直观:对每个可能的轮次 n n n,计算"刚好满足效果约束"所需要的最小每轮用水量 v v v,进而得到总用水量 V ( n ) = n v V(n) = nv V(n)=nv。然后在所有可行方案中选总用水量最小的。这个方法之所以有效,是因为我们已经通过模型二证明了等量分水的最优性,将 n n n 维优化降为了一维枚举。
11.4 MATLAB 实现
%% solve_model.m (模型三主函数)
% 功能:联合优化轮次n和每轮用水量v,求最小总用水量
% 使用解析公式+枚举法
function result3 = solve_model_optimal(params)
w = params.w;
epsilon = params.epsilon;
v_min = params.v_min;
V_max = params.V_max;
n_max = params.n_max;
% 初始化存储
V_record = inf(1, n_max); % 各n对应的总用水量(inf表示不可行)
v_record = zeros(1, n_max); % 各n对应的每轮用水量
feasible = false(1, n_max); % 可行性标记
fprintf('\n=== 模型三:最优轮次与用水量联合优化 ===\n');
fprintf('%-6s %-12s %-12s %-8s\n', '轮次n', '需要用水v(升)', '总水量V(升)', '可行');
fprintf('%s\n', repmat('-', 1, 45));
for n = 1:n_max
% 由约束方程解出需要的最小每轮用水量(解析解)
% (w/(w+v))^n = epsilon => v = w*(epsilon^(-1/n) - 1)
v_needed = w * (epsilon^(-1/n) - 1);
% 检查可行性
if v_needed >= v_min && v_needed <= V_max
V_total = n * v_needed;
V_record(n) = V_total;
v_record(n) = v_needed;
feasible(n) = true;
fprintf('%-6d %-12.3f %-12.3f %-8s\n', n, v_needed, V_total, '✓');
else
fprintf('%-6d %-12.3f %-12s %-8s\n', n, v_needed, '---', '✗');
end
end
% 找最优轮次(总用水量最小)
if all(~feasible)
error('在给定参数范围内无可行方案,请放宽约束');
end
[V_opt, n_opt] = min(V_record);
v_opt = v_record(n_opt);
% 验证:代入递推模型检验结果
v_vec_opt = v_opt * ones(1, n_opt);
result_check = build_model(params, v_vec_opt);
% 计算传统洗衣机用水情况(对比基准)
v_trad = params.v_traditional * ones(1, params.n_traditional);
result_trad = build_model(params, v_trad);
% 节水率
water_saving = (result_trad.V_total - V_opt) / result_trad.V_total * 100;
% 打包输出
result3.n_opt = n_opt;
result3.v_opt = v_opt;
result3.V_opt = V_opt;
result3.final_r = result_check.final_r;
result3.V_record = V_record;
result3.v_record = v_record;
result3.feasible = feasible;
result3.result_trad = result_trad;
result3.water_saving = water_saving;
fprintf('\n=== 最优方案 ===\n');
fprintf('最优轮次 n* = %d 轮\n', n_opt);
fprintf('每轮用水量 v* = %.3f 升\n', v_opt);
fprintf('最优总用水量 V* = %.3f 升\n', V_opt);
fprintf('最终残留率 = %.4f%%(验证值)\n', result_check.final_r*100);
fprintf('\n=== 与传统洗衣机对比 ===\n');
fprintf('传统用水量: %.1f 升,残留率: %.4f%%\n', ...
result_trad.V_total, result_trad.final_r*100);
fprintf('节水率: %.2f%%\n', water_saving);
end
代码解析:
-
epsilon^(-1/n)的计算: 这对应数学推导中 ϵ − 1 / n \epsilon^{-1/n} ϵ−1/n,MATLAB中直接写epsilon^(-1/n)即可,不需要取对数再还原。初学者有时会多此一举地写exp(-log(epsilon)/n),虽然等价但没必要。 -
inf(1, n_max)初始化: 用inf初始化V_record数组,这样min函数会自动忽略不可行方案(因为不可行的元素保持inf),代码更简洁。 -
验证步骤: 找到最优 n ∗ n^* n∗ 和 v ∗ v^* v∗ 之后,调用
build_model重新验证结果,这是一个很好的"闭环验证"习惯。如果解析解计算有误,这一步可以发现。 -
传统洗衣机对比: 对比不是可选项,而是题目要求。要在代码中明确计算传统方案的各项指标,并计算节水率,这在论文中非常有说服力。
11.5 结果解释
以 w = 10 w=10 w=10L、 ϵ = 0.02 \epsilon=0.02 ϵ=0.02(2%残留率)为例,数值结果如下(模拟结果示例):
| 轮次 n n n | 每轮用水量 v v v(升) | 总用水量 V V V(升) | 可行 |
|---|---|---|---|
| 1 | 10 ( 0.02 − 1 − 1 ) ≈ 490 10(0.02^{-1}-1) \approx 490 10(0.02−1−1)≈490 | 490 | ✗(超桶容量) |
| 2 | 10 ( 0.02 − 0.5 − 1 ) ≈ 60.7 10(0.02^{-0.5}-1) \approx 60.7 10(0.02−0.5−1)≈60.7 | 121.4 | ✗(超桶容量) |
| 3 | 10 ( 0.02 − 1 / 3 − 1 ) ≈ 26.9 10(0.02^{-1/3}-1) \approx 26.9 10(0.02−1/3−1)≈26.9 | 80.7 | ✓ |
| 4 | 10 ( 0.02 − 1 / 4 − 1 ) ≈ 18.1 10(0.02^{-1/4}-1) \approx 18.1 10(0.02−1/4−1)≈18.1 | 72.4 | ✓ |
| 5 | 10 ( 0.02 − 1 / 5 − 1 ) ≈ 13.5 10(0.02^{-1/5}-1) \approx 13.5 10(0.02−1/5−1)≈13.5 | 67.5 | ✓ |
| 6 | 10 ( 0.02 − 1 / 6 − 1 ) ≈ 10.7 10(0.02^{-1/6}-1) \approx 10.7 10(0.02−1/6−1)≈10.7 | 64.2 | ✓ |
| 7 | 10 ( 0.02 − 1 / 7 − 1 ) ≈ 8.9 10(0.02^{-1/7}-1) \approx 8.9 10(0.02−1/7−1)≈8.9 | 62.3 | ✓ |
| 8 | 10 ( 0.02 − 1 / 8 − 1 ) ≈ 7.6 10(0.02^{-1/8}-1) \approx 7.6 10(0.02−1/8−1)≈7.6 | 60.8 | ✓ |
| 9 | 10 ( 0.02 − 1 / 9 − 1 ) ≈ 6.6 10(0.02^{-1/9}-1) \approx 6.6 10(0.02−1/9−1)≈6.6 | 59.4 | ✓ |
| 10 | 10 ( 0.02 − 1 / 10 − 1 ) ≈ 5.8 10(0.02^{-1/10}-1) \approx 5.8 10(0.02−1/10−1)≈5.8 | 58.0 | ✓ |
可以看出,随着轮次增加,总用水量单调递减(趋向一个极限值)。理论极限为:
lim n → ∞ V ∗ ( n ) = lim n → ∞ n ⋅ w ( ϵ − 1 / n − 1 ) = − w ln ϵ \lim_{n \to \infty} V^*(n) = \lim_{n \to \infty} n \cdot w(\epsilon^{-1/n} - 1) = -w \ln \epsilon n→∞limV∗(n)=n→∞limn⋅w(ϵ−1/n−1)=−wlnϵ
以 w = 10 w=10 w=10L、 ϵ = 0.02 \epsilon=0.02 ϵ=0.02 代入: lim = − 10 × ln ( 0.02 ) ≈ 39.1 \lim = -10 \times \ln(0.02) \approx 39.1 lim=−10×ln(0.02)≈39.1 升。
这个极限值有深刻的物理意义:无论怎么优化分配策略,节水洗衣机至少需要约39升水(当然,要实现这个极限需要无穷多轮,不切实际)。实际中取 n = 8 n=8 n=8 至 n = 10 n=10 n=10 轮已经非常接近极限,而传统洗衣机用了120升。
十二、算法流程设计
具体相关示意图绘制如下,仅供参考:
流程说明:
整个算法采用模块化设计,各函数职责清晰:
data_preprocess是"配置层",只做参数初始化;build_model是"计算核心",被多处调用;solve_model_*是"优化层",在核心之上做决策;plot_results和sensitivity_analysis是"输出层",不涉及核心计算。
这种分层设计的好处是:修改参数只需改 data_preprocess,修改物理模型只需改 build_model,不会影响其他模块。
十三、MATLAB 完整代码
13.1 主程序 main.m
%% main.m
% 1996年国赛B题"节水洗衣机"完整求解程序
% 运行环境:MATLAB R2019b 及以上
% 运行方法:直接在MATLAB中运行 main.m
clc;
clear;
close all;
fprintf('====================================\n');
fprintf(' 1996国赛B题:节水洗衣机 建模求解\n');
fprintf('====================================\n\n');
%% 步骤一:参数初始化
params = data_preprocess();
%% 步骤二:模型二求解(固定总水量下的最优分配验证)
fprintf('\n【模型二:验证等量分水最优性】\n');
result2 = solve_model_fixed_V(params, 60, 5); % 示例:60升水,5轮
%% 步骤三:模型三求解(最优轮次与水量联合优化)
fprintf('\n【模型三:最优方案求解】\n');
result3 = solve_model_optimal(params);
%% 步骤四:结果可视化
fprintf('\n【生成结果图表】\n');
plot_results(params, result3);
%% 步骤五:灵敏度分析
fprintf('\n【灵敏度分析】\n');
sensitivity_analysis(params);
fprintf('\n====================================\n');
fprintf(' 计算完成!请查看图表窗口。\n');
fprintf('====================================\n');
13.2 数据预处理函数(见第六节,已完整给出)
13.3 模型求解函数(见第九、十、十一节,已完整给出)
13.4 结果可视化函数
%% plot_results.m
% 功能:绘制结果可视化图表
% 图1:各轮次对应的最优总用水量
% 图2:最优方案下各轮残留率变化
% 图3:与传统洗衣机对比
function plot_results(params, result3)
w = params.w;
epsilon = params.epsilon;
n_max = params.n_max;
%% 图1:轮次 vs 最优总用水量
figure('Name', '节水洗衣机优化结果', 'NumberTitle', 'off', ...
'Position', [100, 100, 1200, 400]);
subplot(1, 3, 1);
n_vec = 1:n_max;
V_vec = result3.V_record;
feasible = result3.feasible;
% 理论极限线
V_limit = -w * log(epsilon);
hold on;
% 不可行点(灰色)
plot(n_vec(~feasible), V_vec(~feasible), 'o', ...
'Color', [0.7 0.7 0.7], 'MarkerSize', 8, 'DisplayName', '不可行方案');
% 可行点(蓝色)
plot(n_vec(feasible), V_vec(feasible), 'b-o', ...
'LineWidth', 2, 'MarkerSize', 8, 'MarkerFaceColor', 'b', ...
'DisplayName', '可行方案');
% 最优点(红色星形)
plot(result3.n_opt, result3.V_opt, 'r*', ...
'MarkerSize', 15, 'LineWidth', 2, 'DisplayName', '最优方案');
% 理论极限
yline(V_limit, 'k--', 'LineWidth', 1.5, 'DisplayName', sprintf('理论极限 %.1f升', V_limit));
% 传统洗衣机
yline(result3.result_trad.V_total, 'r:', 'LineWidth', 1.5, ...
'DisplayName', sprintf('传统洗衣机 %.0f升', result3.result_trad.V_total));
hold off;
xlabel('漂洗轮次 n');
ylabel('最优总用水量 V* (升)');
title('轮次 vs 最优总用水量');
legend('Location', 'northeast');
grid on;
ylim([0, result3.result_trad.V_total * 1.1]);
%% 图2:最优方案下各轮残留率变化
subplot(1, 3, 2);
v_opt_vec = result3.v_opt * ones(1, result3.n_opt);
result_opt = build_model(params, v_opt_vec);
rounds = 0:result3.n_opt;
r_values = result_opt.r * 100; % 转为百分比
bar(rounds, r_values, 'FaceColor', [0.2 0.6 0.9], 'EdgeColor', 'none');
hold on;
yline(epsilon * 100, 'r--', 'LineWidth', 2, 'DisplayName', sprintf('允许阈值 %.0f%%', epsilon*100));
plot(rounds, r_values, 'ko-', 'MarkerFaceColor', 'k', 'MarkerSize', 6);
hold off;
xlabel('漂洗轮次');
ylabel('洗涤剂残留率 (%)');
title(sprintf('最优方案残留率变化(n*=%d轮)', result3.n_opt));
legend('Location', 'northeast');
grid on;
%% 图3:与传统洗衣机的对比
subplot(1, 3, 3);
categories = {'传统洗衣机', '节水洗衣机'};
water_vals = [result3.result_trad.V_total, result3.V_opt];
colors = [0.9 0.3 0.3; 0.3 0.7 0.3];
b = bar(categorical(categories), water_vals, 'FaceColor', 'flat');
b.CData = colors;
% 添加数值标签
for i = 1:2
text(i, water_vals(i) + 2, sprintf('%.1f升', water_vals(i)), ...
'HorizontalAlignment', 'center', 'FontSize', 11, 'FontWeight', 'bold');
end
ylabel('总用水量 (升)');
title(sprintf('节水效果对比\n(节水率: %.1f%%)', result3.water_saving));
grid on;
ylim([0, max(water_vals) * 1.2]);
% 残留率对比(右侧小标注)
r_trad = result3.result_trad.final_r * 100;
r_opt = result3.final_r * 100;
annotation('textbox', [0.75, 0.15, 0.2, 0.15], ...
'String', sprintf('残留率比较:\n传统: %.3f%%\n节水: %.3f%%', r_trad, r_opt), ...
'FitBoxToText', 'on', 'BackgroundColor', 'lightyellow');
sgtitle('1996国赛B题:节水洗衣机优化结果', 'FontSize', 14, 'FontWeight', 'bold');
end
代码解析:
-
subplot(1,3,k)布局: 三张图并排,第一张展示优化目标随轮次的变化趋势,第二张展示最优方案的物理过程,第三张直观对比节水效果。这三张图形成了一个完整的"结果叙事"。 -
yline的使用: 用水平参考线标注理论极限和传统洗衣机基准,是数据可视化中的好习惯——让读者一眼看清当前结果与关键基准的关系。 -
颜色设计: 可行方案用蓝色,最优点用红星,传统方案用红色虚线,节水方案用绿色——颜色传递信息(绿色=好,红色=警告/对比基准)。
-
竞赛建议: 在论文中,不要直接截图MATLAB图形,而应该用AI或专业软件重绘,或者在MATLAB中设置好字体大小(至少12pt)、线条粗细和颜色方案,确保图形清晰可读。
13.5 灵敏度分析函数
%% sensitivity_analysis.m
% 功能:分析模型对关键参数的灵敏度
% 分析参数:衣物吸水量w、残留率阈值epsilon
function sensitivity_analysis(params_base)
fprintf('\n=== 灵敏度分析 ===\n');
figure('Name', '灵敏度分析', 'NumberTitle', 'off', 'Position', [100, 100, 1000, 400]);
%% 分析1:吸水量w的影响
subplot(1, 2, 1);
w_range = 5:2:25; % w从5升到25升
V_opt_w = zeros(size(w_range));
n_opt_w = zeros(size(w_range));
for i = 1:length(w_range)
params_temp = params_base;
params_temp.w = w_range(i);
% 重新优化(简化版,直接枚举)
V_min = inf;
n_best = 1;
for n = 1:params_temp.n_max
v_needed = params_temp.w * (params_temp.epsilon^(-1/n) - 1);
if v_needed >= params_temp.v_min && v_needed <= params_temp.V_max
V_total = n * v_needed;
if V_total < V_min
V_min = V_total;
n_best = n;
end
end
end
V_opt_w(i) = V_min;
n_opt_w(i) = n_best;
end
yyaxis left;
plot(w_range, V_opt_w, 'b-o', 'LineWidth', 2, 'MarkerFaceColor', 'b');
ylabel('最优总用水量 V* (升)', 'Color', 'b');
yyaxis right;
plot(w_range, n_opt_w, 'r-s', 'LineWidth', 2, 'MarkerFaceColor', 'r');
ylabel('最优轮次 n*', 'Color', 'r');
xlabel('衣物吸水量 w (升)');
title('吸水量w对最优方案的影响');
grid on;
%% 分析2:残留率阈值epsilon的影响
subplot(1, 2, 2);
eps_range = [0.005, 0.01, 0.02, 0.03, 0.05, 0.08, 0.1];
V_opt_eps = zeros(size(eps_range));
n_opt_eps = zeros(size(eps_range));
for i = 1:length(eps_range)
params_temp = params_base;
params_temp.epsilon = eps_range(i);
V_min = inf;
n_best = 1;
for n = 1:params_temp.n_max
v_needed = params_temp.w * (params_temp.epsilon^(-1/n) - 1);
if v_needed >= params_temp.v_min && v_needed <= params_temp.V_max
V_total = n * v_needed;
if V_total < V_min
V_min = V_total;
n_best = n;
end
end
end
V_opt_eps(i) = V_min;
n_opt_eps(i) = n_best;
end
yyaxis left;
semilogx(eps_range*100, V_opt_eps, 'b-o', 'LineWidth', 2, 'MarkerFaceColor', 'b');
ylabel('最优总用水量 V* (升)', 'Color', 'b');
yyaxis right;
semilogx(eps_range*100, n_opt_eps, 'r-s', 'LineWidth', 2, 'MarkerFaceColor', 'r');
ylabel('最优轮次 n*', 'Color', 'r');
xlabel('允许残留率 ε (%)');
title('残留率阈值ε对最优方案的影响');
grid on;
sgtitle('灵敏度分析:关键参数对最优方案的影响', 'FontSize', 13, 'FontWeight', 'bold');
% 打印灵敏度结论
fprintf('w变化范围: %.0f~%.0f升,对应V*变化范围: %.1f~%.1f升\n', ...
min(w_range), max(w_range), min(V_opt_w), max(V_opt_w));
fprintf('epsilon变化范围: %.1f%%~%.1f%%,对应V*变化范围: %.1f~%.1f升\n', ...
min(eps_range)*100, max(eps_range)*100, min(V_opt_eps), max(V_opt_eps));
end
代码解析:
-
双 Y 轴(
yyaxis)的使用: 因为 V ∗ V^* V∗ 和 n ∗ n^* n∗ 的量纲不同(一个是升,一个是无量纲整数),用双 Y 轴在同一图中展示更直观。 -
semilogx(半对数坐标)的使用: 残留率阈值 ϵ \epsilon ϵ 的变化范围跨越一个数量级(0.5%到10%),用对数坐标可以更清晰地展示小数值区域的变化。 -
灵敏度分析的目的: 告诉评委和读者——我们的模型不是"碰巧"在特定参数下有好结果,而是在合理参数范围内普遍有效。这大大增强了结论的可信度。
十四、结果展示与分析
14.1 主要结果(模拟结果示例)
⚠️ 说明:以下结果为基于假设参数( w = 10 w=10 w=10升, ϵ = 2 \epsilon=2% ϵ=2)的模拟计算结果,不是真实实验数据。
最优方案:
| 指标 | 传统洗衣机 | 节水洗衣机(优化方案) |
|---|---|---|
| 漂洗轮次 | 3轮 | 8~10轮 |
| 每轮用水量 | 40升 | 6~8升 |
| 总用水量 | 120升 | 约58~61升 |
| 最终残留率 | 0.08% | ≤2%(满足标准) |
| 节水率 | — | 约49~52% |
14.2 结果如何对应题目要求
题目要求"总量最少":✅ 我们找到了给定参数下的全局最优解。
题目要求"满足洗涤效果":✅ 残留率恰好满足 ϵ = 2 \epsilon=2% ϵ=2 约束(取等号,即刚好满足,不浪费)。
题目要求"对比传统洗衣机":✅ 节水率约50%,有显著节水效果。
14.3 结果的现实意义
-
节水约50%:每次洗衣可节省约60升水,以一个四口之家每周洗衣3次计算,每年可节约约9000升水,相当于一个中等家庭一个月的生活用水量。
-
轮次增加但更节水:直觉上,“多轮"意味着"更耗水”——但模型证明恰恰相反。每轮少量用水、多轮漂洗的策略,总用水量显著低于传统的每轮大量用水。这是反直觉的结论,也是这道题最有价值的建模发现。
-
理论极限的意义: lim V ∗ = − w ln ϵ \lim V^* = -w\ln\epsilon limV∗=−wlnϵ 告诉我们节水的"物理边界"在哪里,帮助工程师评估技术可行性。
14.4 异常现象说明
-
为什么轮次越多总水量越少,但趋于平缓? 因为 V ∗ ( n ) = n w ( ϵ − 1 / n − 1 ) V^*(n) = nw(\epsilon^{-1/n}-1) V∗(n)=nw(ϵ−1/n−1) 是关于 n n n 的单调递减函数,但递减速率越来越慢,渐近于理论极限。实际工程中,超过8~10轮后收益递减,不值得进一步增加。
-
为什么节水洗衣机的残留率(2%)反而高于传统洗衣机(0.08%)? 因为传统洗衣机"浪费"了大量水来实现远超标准的清洁度。节水洗衣机恰好达标,不多也不少——这才是真正的"优化"。很多初学者误以为"残留率越低越好",但这道题明确要求的是"在满足标准的前提下用水最少",不是"用最多水把衣服洗最干净"。
十五、模型检验
15.1 误差分析
本题为纯机理模型,主要误差来源于模型假设与现实的偏差:
| 误差来源 | 影响方向 | 量级估计 |
|---|---|---|
| 吸水量 w w w 的估计误差 | 直接影响最优 v ∗ v^* v∗ | 若 w w w 估计偏大10%, V ∗ V^* V∗ 偏大约8% |
| 混合均匀假设违反 | 模型偏乐观 | 实际残留率可能高于预测值5%~15% |
| 洗涤剂吸附效应忽略 | 模型偏乐观 | 需要实验数据校正 |
| 脱水效率变化忽略 | 随机误差 | 通常影响较小( < 5 <5% <5) |
误差控制建议:
- 对 w w w 进行保守估计(偏大),确保模型结果偏安全;
- 将标准阈值从2%收紧到1.5%,为混合不均匀留出安全余量。
15.2 灵敏度分析结论
从灵敏度分析结果(模拟)中观察:
对吸水量 w w w 的灵敏度:
- w w w 从5升增加到25升时, V ∗ V^* V∗ 相应地从约29升增加到约145升,近似线性关系。
- 这说明 w w w 是最关键参数,工程实践中应当准确测定。
对残留率阈值 ϵ \epsilon ϵ 的灵敏度:
- ϵ \epsilon ϵ 从0.5%放宽到10%时, V ∗ V^* V∗ 从约80升降至约35升。
- 这给出了一个重要的政策建议:在保证卫生安全的前提下,合理放宽洗涤标准,可以显著降低用水量。
15.3 稳定性分析
对最优方案进行小扰动测试:在 v ∗ v^* v∗ 基础上±10%扰动每轮用水量,观察残留率变化:
r n ′ = ∏ k = 1 n w w + v ∗ ( 1 + δ k ) r_n' = \prod_{k=1}^{n} \frac{w}{w + v^*(1+\delta_k)} rn′=k=1∏nw+v∗(1+δk)w
当 δ k ∈ [ − 0.1 , 0.1 ] \delta_k \in [-0.1, 0.1] δk∈[−0.1,0.1] 时,残留率变化约在 [ − 15 [-15%, +20%] [−15 范围内。说明:
- 向正扰动(多用水):残留率降低,洗涤效果更好;
- 向负扰动(少用水):残留率升高,可能违反约束。
因此,实际控制系统应预留10%~20%的余量,即每轮实际用水量设为 1.1 v ∗ 1.1v^* 1.1v∗~ 1.2 v ∗ 1.2v^* 1.2v∗。
15.4 鲁棒性分析
%% 鲁棒性分析代码片段(包含在sensitivity_analysis.m中)
% Monte Carlo 分析:参数同时扰动下的最优方案稳定性
N_sim = 1000;
V_sim = zeros(N_sim, 1);
for i = 1:N_sim
params_mc = params_base;
% 对w进行±20%随机扰动
params_mc.w = params_base.w * (1 + 0.2*(2*rand()-1));
% 求最优解
V_min = inf;
for n = 1:params_mc.n_max
v_n = params_mc.w * (params_mc.epsilon^(-1/n) - 1);
if v_n >= params_mc.v_min && v_n <= params_mc.V_max
V_total = n * v_n;
if V_total < V_min
V_min = V_total;
end
end
end
V_sim(i) = V_min;
end
fprintf('Monte Carlo鲁棒性分析(N=%d次):\n', N_sim);
fprintf(' 最优总水量均值: %.2f升\n', mean(V_sim));
fprintf(' 标准差: %.2f升\n', std(V_sim));
fprintf(' 95%%置信区间: [%.2f, %.2f]升\n', quantile(V_sim, 0.025), quantile(V_sim, 0.975));
十六、模型优缺点
16.1 模型优点
优点一:物理机制清晰。 递推方程直接来自质量守恒和稀释原理,不依赖黑箱方法,结果具有物理可解释性。
优点二:解析解优雅。 通过均值不等式证明了等量分水的最优性,将高维优化问题降为一维枚举,计算效率极高。
优点三:给出了理论极限。 lim V ∗ = − w ln ϵ \lim V^* = -w\ln\epsilon limV∗=−wlnϵ 这个解析结果告诉工程师"节水潜力的物理上界",对产品设计有直接指导意义。
优点四:对比分析完整。 模型不仅给出节水方案,还与传统洗衣机进行定量对比,结论具有实用价值。
16.2 模型缺点与改进方向
缺点一:均匀混合假设过强。 实际漂洗中,洗涤剂在衣物纤维中的分布是不均匀的,简单稀释模型高估了漂洗效率。
改进方向: 引入"有效混合率" η ∈ ( 0 , 1 ) \eta \in (0,1) η∈(0,1),将递推方程修改为:
m k = m k − 1 ⋅ w w + η v k m_k = m_{k-1} \cdot \frac{w}{w + \eta v_k} mk=mk−1⋅w+ηvkw
缺点二:忽略了洗涤剂在纤维中的物理吸附。 有些洗涤剂分子会被纤维吸附,不能被简单冲洗去除。
改进方向: 引入吸附动力学模型(如Langmuir等温线),建立更真实的多相传质模型。
缺点三:单一目标优化。 只考虑节水,没有考虑时间成本(轮次多则时间长)和电能消耗。
改进方向: 构建多目标优化模型:
min V t o t a l , T t o t a l , E t o t a l \min {V_{total}, T_{total}, E_{total}} minVtotal,Ttotal,Etotal
使用Pareto前沿分析,为消费者提供可选择的"偏好方案"(如偏好省水型、偏好省时型)。
缺点四:参数假设未经实验验证。 w w w、 ϵ \epsilon ϵ 等参数来自估计,结论的精度依赖于参数精度。
改进方向: 建议开展实测实验,用实测数据校准 w w w 参数,并用留一法交叉验证模型预测精度。
十七、论文写作建议
17.1 摘要写法
摘要是论文的"门面",评委通常先看摘要决定是否仔细阅读。数学建模竞赛摘要需要在300~500字内回答以下问题:
- 这道题是什么类型的问题?
- 针对每个子问题,你建立了什么模型?
- 用什么方法求解?
- 得到了什么关键结论?
- 这个结论有什么实际意义?
摘要写法误区: 很多同学把摘要写成"本文研究了节水洗衣机问题,建立了数学模型,经过计算得出了结论"——这等于什么都没说。摘要必须有具体数字和具体结论。
17.2 关键词选择
好的关键词应覆盖:问题类型 + 模型名称 + 核心方法
例如:节水优化、差分递推模型、均值不等式、参数灵敏度分析、多轮漂洗策略
17.3 问题重述写法
问题重述≠题目复述。题目复述是把题目原文抄一遍,而问题重述是用自己的数学语言重新描述问题。
好的问题重述应包含:
- 已知什么(量化表达);
- 求什么(用数学符号);
- 约束是什么。
17.4 模型假设写法
每条假设必须包含:
- 假设内容(是什么);
- 为什么需要(为什么);
- 违反后的影响(局限性)。
不要写"假设洗涤效果良好"这样的废话假设。
17.5 符号说明写法
符号表要完整、统一,且与正文完全一致。建议使用LaTeX格式,表格对齐,每个符号都有量纲。
17.6 模型建立写法
不要一上来就列公式。写模型建立时,应该先用自然语言描述建模思路,再引出公式,公式后紧跟参数解释。
17.7 结果分析写法
结果分析不是"结果表格 + 一句’结果合理’"。应包含:数值说明、现实解释、图表指向、异常讨论、结论提炼。
17.8 参考文献写法
注意:参考文献要真实存在,不要凭空捏造。建议引用:
- 相关教材(运筹学、数学建模教材);
- 洗涤化学领域的综述文章;
- 已发表的相关建模论文。
17.9 附录代码整理方式
附录中的代码应:
- 按模块分类整理,不要一整段;
- 保留中文注释;
- 标注运行环境(MATLAB版本);
- 说明如何运行(运行哪个文件,输入什么参数)。
十八、数学建模论文摘要示例
以下是符合数学建模竞赛风格的中文摘要示例,供参考。
摘要
本文针对1996年全国大学生数学建模竞赛B题"节水洗衣机",建立了基于浓度递推原理的洗涤过程数学模型,并通过解析推导与数值优化,给出了满足洗涤效果约束下总用水量最小的最优控制策略。
针对问题一,基于质量守恒定律和均匀混合假设,建立了洗涤剂残留量的差分递推方程: m k = m k − 1 ⋅ w / ( w + v k ) m_k = m_{k-1} \cdot w/(w+v_k) mk=mk−1⋅w/(w+vk),并推导出 n n n 轮后残留率的乘积公式 r n = ∏ k = 1 n w / ( w + v k ) r_n = \prod_{k=1}^{n} w/(w+v_k) rn=∏k=1nw/(w+vk)。该公式揭示了漂洗效果与各轮加水量的定量关系。
针对问题二,利用算术-几何均值不等式,严格证明了在总用水量 V V V 和轮次 n n n 固定的条件下,各轮平均分配用水量( v i = V / n v_i = V/n vi=V/n)是使最终残留率最低的最优策略,同时使残留率达到解析最小值 r n ∗ = [ w / ( w + V / n ) ] n r_n^* = [w/(w+V/n)]^n rn∗=[w/(w+V/n)]n。
针对问题三,基于等量分水最优结论,建立了最优轮次与最优用水量的联合优化模型。通过对轮次 n n n 的整数枚举,解析给出每一轮次下满足约束的最小用水量 v ∗ ( n ) = w ( ϵ − 1 / n − 1 ) v^*(n) = w(\epsilon^{-1/n}-1) v∗(n)=w(ϵ−1/n−1),进而确定全局最优方案。当衣物吸水量 w = 10 w=10 w=10 升、残留率标准 ϵ = 2 \epsilon=2% ϵ=2 时,最优方案为漂洗 8~10轮、每轮用水约 6~8升,总用水量约 58~61升,较传统洗衣机(3轮×40升=120升)节水约 49%~52%。同时推导出最优总用水量的理论下界 V m i n = − w ln ϵ ≈ 39.1 V_{min} = -w\ln\epsilon \approx 39.1 Vmin=−wlnϵ≈39.1 升。
模型的灵敏度分析表明,结果对吸水量参数 w w w 较为敏感,建议在工程实现中预留10%~20%的水量余量。模型假设的主要局限性在于均匀混合假设,实际工程中可通过引入有效混合率加以修正。
关键词:节水优化;洗涤剂浓度递推;均值不等式;最优轮次;参数灵敏度分析
十九、常见问题与踩坑总结
Q1:拿到数学建模题目后为什么不能马上写代码?
这是最经典的误区。拿到题目立刻打开MATLAB的同学,通常会在写了一半代码后发现:我不知道这个函数的输出是什么,我不知道这个变量的物理意义,我不知道约束条件是什么。
正确的顺序是:读题→理解物理机制→定义变量→建立数学模型→确定求解方法→写代码。代码是数学模型的翻译,必须先有模型才能写代码。从题目到代码,中间有三层(问题理解→数学建模→算法设计),每一层都不能跳过。
Q2:问题重述和题目复述有什么区别?
题目复述是"把原题抄一遍",而问题重述是"用数学语言重新描述问题"。
以本题为例:
- 复述:“请为洗衣机设计一种程序,使得在满足一定洗涤效果的条件下,总量最少。”
- 重述:“设第 k k k 轮加水量为 v k v_k vk,衣物吸附水量为 w w w,洗涤效果标准为 r n ≤ ϵ r_n \leq \epsilon rn≤ϵ,求最优决策 ( n ∗ , v 1 ∗ , … , v n ∗ ∗ ) (n^*, v_1^*, \ldots, v_{n^*}^*) (n∗,v1∗,…,vn∗∗) 使 ∑ v k \sum v_k ∑vk 最小。”
重述的核心是数学化,不是长度。
Q3:模型假设是不是越多越好?
不是。假设的数量不重要,质量才重要。每条假设都应该是建立后续模型所必需的,而不是为了凑数。
错误示范:假设1:洗衣机正常运行。假设2:衣物是干净的。(这些假设对建模毫无帮助)
正确做法:只写那些"如果去掉这条假设,模型就无法建立或需要大幅修改"的假设。
Q4:为什么公式很多但论文依然得分不高?
公式多不等于模型好。评委看的是:
- 公式从何而来(推导过程);
- 公式变量是什么(定义清晰);
- 公式说明了什么(含义解释);
- 公式如何求解(算法说明);
- 结果如何解读(分析讨论)。
"公式堆砌"是数学建模论文中的大忌。一个推导严谨、解释清晰的模型,远比一堆晦涩无解释的公式有价值。
Q5:MATLAB代码结果如何对应论文表格?
代码结果→论文表格需要一一对应,且表格标题应该说明数据来源和计算条件。
实践建议:在代码中使用 fprintf 或 writetable 直接输出格式化表格,复制到论文时只需调整格式。同时在论文中注明"表X由MATLAB计算得出,参数设置见附录A"。
Q6:没有附件数据时如何构建合理分析框架?
没有数据时,应该:
- 从物理/工程第一性原理推导模型;
- 查阅文献获取参数的合理范围;
- 用参数范围内的典型值计算结果;
- 通过灵敏度分析展示结果对参数的依赖性。
最忌讳的是"拍脑袋"给出参数然后假装数据是真实的——评委能看出来。
Q7:预测模型如何选择误差指标?
选择误差指标要根据数据特性:
- 如果数据中有极端值(异常值),用MAE(对异常值不敏感);
- 如果需要惩罚大误差,用RMSE(对大误差更敏感);
- 如果需要反映相对误差,用MAPE(百分比形式,便于解释);
- 如果需要综合评价拟合优度,用R²。
不要在同一论文中只用一种指标,建议报告至少2~3种。
Q8:评价模型中权重如何确定?
权重确定是评价模型的核心,主要方法有:
- 主观法:德尔菲法、层次分析法(AHP);
- 客观法:熵权法、CRITIC法、主成分分析;
- 组合法:将主观权重和客观权重加权平均。
选择哪种方法要根据题目情境:有专家意见时用主观法,只有数据时用客观法,两者都有时用组合法。无论哪种方法,都要在论文中说明权重的合理性,不能"拍脑袋给权重"。
Q9:优化模型如何确定目标函数和约束条件?
目标函数来自题目中"最大/最小化什么",约束条件来自题目中"满足什么条件"。
提炼方法:“从题目中找所有量→分类为决策变量、约束参数和目标→建立关系”。
常见误区:把约束条件混入目标函数,或把目标函数变成约束条件。本题中"用水量最小"是目标,"残留率≤ε"是约束,不能反过来。
Q10:国赛论文和美赛论文写法有什么区别?
| 维度 | 国赛 | 美赛 |
|---|---|---|
| 语言 | 中文 | 英文 |
| 结构 | 较固定(必须有摘要、假设、符号等标准章节) | 相对灵活,但需有Summary Sheet |
| 摘要 | 约300~500字,位于首页 | 约400~600字,作为独立Summary Sheet |
| 图表 | 规范即可 | 要求较高,应有标题、来源标注 |
| 代码 | 通常放附录 | 通常放附录,有时要求链接或说明 |
| 风格 | 严谨学术 | 更注重创新性和"讲故事"能力 |
Q11:如何避免论文像代码说明书?
“代码说明书"型论文的特征:每段都是"这段代码定义了变量X,然后计算了Y,输出了Z”。
避免的方法:写论文时,以数学模型为主线,代码只是实现工具,放附录。正文中说的是"建立了什么模型,用什么方法求解,得到了什么结论",不是"写了什么代码"。
Q12:如何写出高质量摘要?
参照"SCR结构":Situation(背景)→Challenge(问题)→Resolution(解决方案)→Result(结论)。
每个部分控制在12句,整体300500字,包含具体数字和具体结论。
Q13:如何自然地提出模型改进?
改进建议要从"模型的局限性"出发,而不是凭空提出。先分析"这个假设在什么情况下会失效",再提出"如何修正"。
例如:本题中,均匀混合假设在快速漂洗时会失效,改进方向是引入"混合效率参数 η \eta η",并通过实验校定。这比说"可以用更好的算法"要具体得多。
Q14:模型优缺点如何写得具体?
优缺点不能只写"计算简单"、"假设合理"这种废话。应该写:
- 优点:因为XX原因,这个模型在YY情况下比ZZ方法好/快/准;
- 缺点:因为AA假设,当BB条件不满足时,模型误差会达到CC量级。
要有对比对象,要有量化说明。
Q15:附录代码应该如何整理?
- 按功能模块分段,每段有标题注释;
- 删去调试用的临时代码;
- 保留数据读取、核心计算、结果输出三个主要部分;
- 说明运行方法(运行哪个文件,期望输出什么);
- 如有多个函数文件,说明调用关系。
二十、总结
回顾整篇解析,我们从1996年这道看似简单的洗衣机题中,挖掘出了一套完整的建模思路:
核心建模发现:
-
物理机制决定模型结构:洗涤过程是离散稀释过程,自然导出差分递推方程,这是整个模型的基石。
-
数学工具化简优化维度:均值不等式的应用将 n n n 维分配问题化简为一维枚举,这是数学工具改变问题难度的典型案例。
-
解析解提供深刻洞见: V m i n = − w ln ϵ V_{min} = -w\ln\epsilon Vmin=−wlnϵ 这个优美的极限公式,不仅是计算结果,更是设计洗衣机时评估技术潜力的理论工具。
-
反直觉结论最有价值:“多轮少量"优于"少轮多量”——这个反直觉的结论,正是这道题最核心的建模价值所在。
给备赛同学的几句话:
数学建模竞赛考察的不是你会多少数学方法,而是你能不能用数学方法解决实际问题。建模能力的核心是从现实到数学的翻译能力——能把物理过程写成方程,能把工程约束写成不等式,能把优化目标写成函数。
这道题的物理过程(稀释)、数学工具(均值不等式)、求解策略(枚举+解析),都是可以迁移到其他问题的通用能力。希望你读完这篇文章,不仅学会了这道题,更建立起了一套可复用的建模思维框架。
加油,你比自己想象的更有潜力!
声明:以上内容部分基于人工智能辅助生成,仅供参考交流,不构成任何专业建议。模型输出可能存在偏差,使用前请自行核实,后果自负。欢迎理性讨论。
若需原题 PDF、附件或历年高教社杯真题,关注技术号 「猿圈奇妙屋」,回复【高教社杯】即可获取。
🎁 文末福利
本专栏内容源自实际建模经验、竞赛题目及读者需求。如涉及版权问题,请告知,将立即处理。部分解法思路参考了网络优秀文章,若未能完全契合你的场景,欢迎在评论区分享更优解法,共同探讨、共同进步!
更多建模方法、工具与竞赛题解,欢迎访问专栏 👉 《《滚雪球学数学建模(含历年真题)》
如果本文对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!
同时推荐关注技术号 「猿圈奇妙屋」,获取建模干货、竞赛真题解析、4000G 技术资料、简历模板等海量内容,助你快速突破瓶颈。
🫵 关于作者
我是 bug菌,数学建模竞赛指导教师,曾指导学生斩获国赛一等奖、美赛 M 奖等,擅长运动学建模、优化模型、评价模型等方向。
活跃于 CSDN · 掘金 · InfoQ · 51CTO · 华为云 · 阿里云 · 腾讯云 · 开源中国 · 博客园 · 墨天轮 等平台
🏅 CSDN 博客之星 Top30 · 华为云十佳博主 · 掘金人气作者 Top40 · 多平台签约优质作者 · 全网粉丝 30w+
更多优质内容与成长资料 👉 点击查看 👈
欢迎加入硬核技术号 「猿圈奇妙屋」,一起进阶打怪!
- End -
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)