🏆 本文已收录于专栏:《滚雪球学数学建模(含历年真题)》

本专栏面向数学建模竞赛学习者,系统覆盖真题解析、建模方法、算法实现、论文写作与 AI 辅助建模等核心环节。无论是建模新手,还是备战华为杯、高教社杯、华数杯、国赛、美赛 MCM/ICM 的参赛者,都能在这里找到清晰、完整、可复用的建模思路,持续更新,长期有效。

🎯 免责声明: 本文题目来源于互联网公开内容,仅供学习交流与建模方法研究,不构成竞赛指导。请遵守相关赛事规则,独立完成竞赛作品,使用本文内容所产生的后果由使用者自行承担。

🎉 专栏限时优惠中:一次订阅,永久解锁,后续内容持续更新。 欢迎点击了解 👉 查看专栏详情 👈

全文目录:

1998A题:投资的收益和风险

真题展示

如下为原(真)题,展示如下:

一、前言:为什么这道题值得深入分析?

作为一名长期指导数学建模竞赛的老师,我每年都会让学生把1998年国赛A题《投资的收益和风险》作为入门必刷真题。原因很简单:这道题是一道教科书级别的多目标线性规划题,涵盖了建模竞赛中最核心的三种能力——问题抽象、模型建立、优化求解。

很多同学第一次看到这道题,会觉得"不就是选资产分配比例吗?写几个不等式然后用linprog跑一下就行了吧?"——这种想法恰恰是建模初学者最常犯的错误。

真正的难点在于:

  • 收益和风险本质上是两个相互冲突的目标,如何在数学上统一处理?
  • 交易费用的非线性分段性如何处理?(购买额不超过 u i u_i ui 时按 u i u_i ui 计算,超过则按比例)
  • 如何定义"总体风险"?题目给的是"所投资的 S i S_i Si 中最大的一个风险"——这是一个 minimax 问题!
  • 如何从单一约束下的最优解过渡到多目标权衡的 Pareto 前沿?

这道题26年后的今天依然是经典,值得每一位建模学习者认真研读。

二、题目背景与现实意义

2.1 现实背景

投资组合优化是金融数学的核心问题之一。1952年,哈里·马科维茨(Harry Markowitz)提出了均值-方差模型,开创了现代投资组合理论,并因此获得1990年诺贝尔经济学奖。

本题在马科维茨框架的基础上做了适当简化,将风险从"收益方差"改为"风险损失率",同时引入了现实中真实存在的交易费用机制,使模型更贴近实际投资场景。

2.2 核心矛盾

投资的核心矛盾永远是:高收益伴随高风险

  • 银行存款:无风险,但收益低( r 0 = 5 r_0 = 5% r0=5
  • 风险资产:收益高,但可能亏损
  • 交易费用:实际净收益会被交易成本压缩

一个理性的投资者希望:在控制风险的前提下,尽可能提高净收益。这就是本题的核心建模目标。

2.3 现实意义

  • 为基金经理提供量化的资产配置建议
  • 帮助个人投资者理性分散投资
  • 为风险管理提供数学依据
  • 是线性规划在金融领域最直接的应用之一

三、题目重述

3.1 已知条件

设市场上有 n n n 种资产 S i S_i Si i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n),供投资者选择。某公司有资金总额 M M M(元)可供投资。

对每种资产 S i S_i Si,财务分析人员给出了如下参数:

参数 含义
r i r_i ri(%) 在该时期内购买 S i S_i Si平均收益率
q i q_i qi(%) 购买 S i S_i Si风险损失率(预测值)
p i p_i pi(%) 购买 S i S_i Si交易费率
u i u_i ui(元) 交易费用计算的阈值,购买额 ≤ u i \leq u_i ui 时按 u i u_i ui 计算手续费

交易费用规则(关键!):

c i = { p i ⋅ u i , 若购买额  x i ≤ u i   p i ⋅ x i , 若购买额  x i > u i c_i = \begin{cases} p_i \cdot u_i, & \text{若购买额 } x_i \leq u_i \ p_i \cdot x_i, & \text{若购买额 } x_i > u_i \end{cases} ci={piui,若购买额 xiui pixi,若购买额 xi>ui

其中 x i x_i xi 为投入到资产 S i S_i Si 的金额。

银行存款:

  • 存款利率 r 0 = 5 r_0 = 5% r0=5,无交易费用,无风险

风险度量:

  • 总体风险 = 所投资的 S i S_i Si最大的单项风险(注意:是风险损失率 q i q_i qi 和投入金额的乘积与总资金的比值)

3.2 待解决问题

问题一(n=4的具体案例):

给定 n = 4 n=4 n=4 时的数据(见图中第一张表),设计一种投资组合方案,用资金 M M M 有选择地购买若干种资产或存入银行,使得:

  • 净收益尽可能大
  • 总体风险尽可能小

问题二(n=15的一般化讨论):

用第二张表( n = 15 n=15 n=15)的数据,对上述问题进行一般性讨论,给出通用投资策略。

3.3 附件数据说明

本题数据直接嵌入题目正文,分两组:

数据组一(n=4):

S i S_i Si r i r_i ri(%) q i q_i qi(%) p i p_i pi(%) u i u_i ui(元)
S 1 S_1 S1 28 2.5 1 103
S 2 S_2 S2 21 1.5 2 198
S 3 S_3 S3 23 5.5 4.5 52
S 4 S_4 S4 25 2.6 6.5 40

数据组二(n=15):

S i S_i Si r i r_i ri(%) q i q_i qi(%) p i p_i pi(%) u i u_i ui(元)
S 1 S_1 S1 9.6 42 2.1 181
S 2 S_2 S2 18.5 54 3.2 407
S 3 S_3 S3 49.4 60 6.0 428
S 4 S_4 S4 23.9 42 1.5 549
S 5 S_5 S5 8.1 1.2 7.6 270
S 6 S_6 S6 14 39 3.4 397
S 7 S_7 S7 40.7 68 5.6 178
S 8 S_8 S8 31.2 33.4 3.1 220
S 9 S_9 S9 33.6 53.3 2.7 475
S 10 S_{10} S10 36.8 40 2.9 248
S 11 S_{11} S11 11.8 31 5.1 195
S 12 S_{12} S12 9 5.5 5.7 320
S 13 S_{13} S13 35 46 2.7 267
S 14 S_{14} S14 9.4 5.3 4.5 328
S 15 S_{15} S15 15 23 7.6 131

四、问题分析

4.1 问题一分析

拿到 n = 4 n=4 n=4 的问题,很多同学会立刻想:直接枚举所有分配方案就行。这是典型的错误思路。

实际上,投资金额是连续变量,不能枚举。核心在于:

目标一:最大化净收益

净收益 = 投资收益 - 交易费用 + 存款收益

注意:交易费用是分段函数,直接处理会导致非线性,需要线性化处理。

x i > 0 x_i > 0 xi>0 时,我们可以合理假设公司投资额 M M M 较大,使得对多数资产有 x i > u i x_i > u_i xi>ui(后面会验证),从而将交易费统一为 p i ⋅ x i p_i \cdot x_i pixi,得到线性模型。

目标二:最小化总体风险

题目明确说:总体风险 = 所投资 S i S_i Si最大的一个风险来度量。

这意味着:

KaTeX parse error: Expected '}', got '\right' at position 64: … \cdot x_i / M \̲r̲i̲g̲h̲t̲}

这是一个 minimax 形式,可以通过引入辅助变量转化为线性约束。

关键洞察: 这是一个**多目标线性规划(MOLP)**问题,不存在唯一最优解,而是一个 Pareto 前沿(权衡曲线)。

4.2 问题二分析

问题二要求"一般情况讨论",实际上是要求:

  1. 建立适用于任意 n n n 的通用模型
  2. n = 15 n=15 n=15 的数据求解
  3. 分析风险偏好参数对投资策略的影响
  4. 给出实际意义解释

额外挑战: n = 15 n=15 n=15 时数据量大,需要在 MATLAB 中批量处理,且需要绘制**有效前沿(Efficient Frontier)**来可视化风险-收益权衡关系。

4.3 各问题之间的逻辑关系

具体相关示意图绘制如下,仅供参考:

问题一是问题二的特例验证,建模框架完全一致,只是数据规模不同。先做好问题一,再推广到问题二,这是标准的建模推进路径。

五、整体建模思路

5.1 建模路线

具体相关示意图绘制如下,仅供参考:

5.2 模型选择依据

候选模型 适用性 本题是否采用
线性规划 目标和约束均线性,直接适用 ✅ 核心模型
二次规划 马科维茨方差模型,需要协方差矩阵 ❌ 本题不给协方差数据
动态规划 多阶段决策问题 ❌ 本题是单期投资
整数规划 决策变量为整数时使用 ❌ 投资金额为连续变量
多目标进化算法 复杂非线性多目标问题 ❌ 本题已能线性化,不必要

结论:本题是标准的多目标线性规划(MOLP),通过约束法转化为单目标LP,用MATLAB的 linprog 函数求解。

5.3 算法实现思路

处理多目标问题最常用的方法有三种:

方法一: ϵ \epsilon ϵ-约束法(本文主要使用)

  • 固定风险上界 a a a,最大化收益
  • 循环改变 a a a 值,得到 Pareto 前沿

方法二:加权法

  • 构造 min ⁡ λ ⋅ Risk − ( 1 − λ ) ⋅ Return \min \lambda \cdot \text{Risk} - (1-\lambda) \cdot \text{Return} minλRisk(1λ)Return
  • 循环改变权重 λ \lambda λ,得到不同偏好下的最优解

方法三:分级优化法

  • 先优化主目标,再在约束范围内优化次目标

5.4 结果验证方法

  1. 检验约束满足性(资金总额约束、非负约束)
  2. 验证交易费线性化假设成立( x i > u i x_i > u_i xi>ui
  3. 绘制 Pareto 前沿,检验单调性(风险越大收益越高)
  4. 与银行存款基准(5%纯收益)比较

六、数据预处理

6.1 数据说明

本题数据直接嵌入题目,无需从文件读取。但在 MATLAB 中,我们将数据规范整理为矩阵形式,便于程序处理。

数据包含4个字段,对应4个参数向量: r \mathbf{r} r q \mathbf{q} q p \mathbf{p} p u \mathbf{u} u

6.2 单位统一处理

注意:题目中 r i r_i ri q i q_i qi p i p_i pi 的单位是百分比(%),在计算时需除以100,转换为小数。

6.3 交易费线性化处理(重要!)

原始交易费规则:

c i ( x i ) = { p i ⋅ u i , x i ≤ u i   p i ⋅ x i , x i > u i c_i(x_i) = \begin{cases} p_i \cdot u_i, & x_i \leq u_i \ p_i \cdot x_i, & x_i > u_i \end{cases} ci(xi)={piui,xiui pixi,xi>ui

这是分段线性函数,直接代入会导致模型非线性。

线性化策略:

观察到当 x i > u i x_i > u_i xi>ui 时, c i = p i x i c_i = p_i x_i ci=pixi,净收益率变为 r i − p i r_i - p_i ripi

x i ≤ u i x_i \leq u_i xiui 时, c i = p i u i c_i = p_i u_i ci=piui,但由于 M M M 通常远大于 u i u_i ui u i u_i ui 最大不过几百元,而 M M M 是公司资金规模),实际投资 x i x_i xi 通常 ≫ u i \gg u_i ui,因此可以合理近似

c i ≈ p i x i (当  x i ≫ u i 时) c_i \approx p_i x_i \quad \text{(当 } x_i \gg u_i \text{时)} cipixi(当 xiui时)

线性化净收益率: r ~ i = r i − p i \tilde{r}_i = r_i - p_i r~i=ripi

严格处理时(若 x i x_i xi 较小):可引入0-1决策变量,用混合整数线性规划处理,但对于大规模投资,近似已足够精确。

本文同时给出两种处理方式

6.4 数据可视化分析

在建模前,先对数据做可视化分析,这一步在实际竞赛中非常重要,但很多同学会跳过。

具体相关示意图绘制如下,仅供参考:

从散点图中可以初步判断:哪些资产"性价比高"(高收益低风险),哪些是"劣势资产"(低收益高风险)。

七、模型假设

在正式建立模型前,必须明确假设条件。假设不是越多越好,而是要有针对性、可验证、服务于后续模型。

假设1: 公司投资总金额为 M M M,所有资金必须全部用于投资(存入银行也是投资的一种形式),即:

x 0 + ∑ i = 1 n x i + ∑ i = 1 n c i ( x i ) = M x_0 + \sum_{i=1}^{n} x_i + \sum_{i=1}^{n} c_i(x_i) = M x0+i=1nxi+i=1nci(xi)=M

其中 x 0 x_0 x0 为存入银行的金额。

假设2: 投资为单期决策,不考虑再投资和动态调整。

假设3: 各资产的收益率 r i r_i ri、风险率 q i q_i qi 为财务分析预测值,视为已知确定量(不考虑参数的不确定性)。

假设4: 各资产之间相互独立,不考虑资产间的相关性(协方差)。

假设5: M M M 足够大时,对实际投入资产 i i i 的金额 x i ≫ u i x_i \gg u_i xiui,交易费用近似为 c i = p i x i c_i = p_i x_i ci=pixi(线性化处理)。

假设6: 风险度量采用题目定义的方式,即总体风险 = 已投资资产中 q i x i / M q_i x_i / M qixi/M 的最大值。

假设7: 决策变量 x i ≥ 0 x_i \geq 0 xi0(不允许卖空)。

八、符号说明

符号 含义 单位
n n n 风险资产总数
M M M 公司总投资资金
x i x_i xi 投入资产 S i S_i Si 的金额, i = 1 , . . . , n i=1,...,n i=1,...,n
x 0 x_0 x0 存入银行的金额
r i r_i ri 资产 S i S_i Si 的平均收益率
q i q_i qi 资产 S i S_i Si 的风险损失率
p i p_i pi 资产 S i S_i Si 的交易费率
u i u_i ui 资产 S i S_i Si 的交易费阈值
r 0 r_0 r0 银行存款利率, r 0 = 0.05 r_0 = 0.05 r0=0.05
r ~ i \tilde{r}_i r~i 资产 S i S_i Si 的净收益率, r ~ i = r i − p i \tilde{r}_i = r_i - p_i r~i=ripi
c i c_i ci 购买资产 S i S_i Si 的交易费用
a a a 总体风险上界(控制参数)
Q Q Q 总体风险度量值
W W W 总净收益
λ \lambda λ 风险偏好权重, λ ∈ [ 0 , 1 ] \lambda \in [0,1] λ[0,1]

九、模型一:基础模型(固定风险上界,最大化收益)

9.1 模型思想

这是解决多目标冲突最常用的方法之一—— ϵ \epsilon ϵ-约束法。

将"最小化风险"转化为约束条件:规定总体风险不超过某个上界 a a a,然后在此约束下最大化净收益。通过改变 a a a 的值,可以得到不同风险偏好下的最优投资方案,从而描绘出完整的 Pareto 前沿。

为什么用这个方法? 因为它直觉上最清晰:投资者可以根据自己的风险承受能力设定 a a a,然后找最优方案。

9.2 数学表达式

决策变量: x 0 , x 1 , x 2 , . . . , x n ≥ 0 x_0, x_1, x_2, ..., x_n \geq 0 x0,x1,x2,...,xn0

目标函数(最大化净收益):

max ⁡ W = r 0 x 0 + ∑ i = 1 n ( r i − p i ) x i \max \quad W = r_0 x_0 + \sum_{i=1}^{n} (r_i - p_i) x_i maxW=r0x0+i=1n(ripi)xi

其中:

  • r 0 x 0 r_0 x_0 r0x0:银行存款收益
  • ( r i − p i ) x i (r_i - p_i) x_i (ripi)xi:资产 i i i 的净收益(扣除交易费后)

约束条件:

资金平衡约束(资金全部用尽):

x 0 + ∑ i = 1 n ( 1 + p i ) x i = M x_0 + \sum_{i=1}^{n} (1 + p_i) x_i = M x0+i=1n(1+pi)xi=M

注意:实际投入资产 i i i 的总成本为 x i + p i x i = ( 1 + p i ) x i x_i + p_i x_i = (1+p_i)x_i xi+pixi=(1+pi)xi,加上存款后等于 M M M

风险约束(minimax转化):

原始风险定义: Q = max ⁡ i q i x i / M Q = \max_i {q_i x_i / M} Q=maxiqixi/M

令辅助变量 a a a 为风险上界,则:

q i x i M ≤ a , ∀ i = 1 , 2 , . . . , n \frac{q_i x_i}{M} \leq a, \quad \forall i = 1, 2, ..., n Mqixia,i=1,2,...,n

即:

q i x i ≤ a ⋅ M , ∀ i q_i x_i \leq a \cdot M, \quad \forall i qixiaM,i

非负约束:

x i ≥ 0 , i = 0 , 1 , . . . , n x_i \geq 0, \quad i = 0, 1, ..., n xi0,i=0,1,...,n

9.3 完整线性规划模型

max ⁡ W = r 0 x 0 + ∑ i = 1 n r ~ i x i \max \quad W = r_0 x_0 + \sum_{i=1}^{n} \tilde{r}_i x_i maxW=r0x0+i=1nr~ixi

s.t. { x 0 + ∑ i = 1 n ( 1 + p i ) x i = M   q i x i ≤ a ⋅ M , i = 1 , . . . , n   x i ≥ 0 , i = 0 , 1 , . . . , n \text{s.t.} \begin{cases} x_0 + \sum_{i=1}^{n} (1+p_i) x_i = M \ q_i x_i \leq a \cdot M, & i = 1,...,n \ x_i \geq 0, & i = 0,1,...,n \end{cases} s.t.{x0+i=1n(1+pi)xi=M qixiaM,i=1,...,n xi0,i=0,1,...,n

其中 r ~ i = r i − p i \tilde{r}_i = r_i - p_i r~i=ripi a a a 为给定的风险控制参数。

9.4 参数解释

  • a a a 的含义: 投资者愿意承受的最大风险比例。 a = 0 a=0 a=0 表示零风险(全存银行), a = 0.05 a=0.05 a=0.05 表示接受5%的最大风险损失比例。
  • ( 1 + p i ) x i (1+p_i)x_i (1+pi)xi 表示购买资产 i i i 的"全成本",包括本金 x i x_i xi 和手续费 p i x i p_i x_i pixi
  • q i x i / M q_i x_i / M qixi/M 资产 i i i 带来的风险占总资金的比例。

9.5 求解方法

本模型是标准线性规划,用 MATLAB 的 linprog 函数求解。

linprog 求解最小化问题,因此目标函数取负:

min ⁡ − W = − r 0 x 0 − ∑ i = 1 n r ~ i x i \min \quad -W = -r_0 x_0 - \sum_{i=1}^{n} \tilde{r}_i x_i minW=r0x0i=1nr~ixi

9.6 MATLAB 实现

data_preprocess.m

function data = data_preprocess(problem_type)
% 数据预处理函数
% 输入: problem_type = 1 表示n=4的问题, problem_type = 2 表示n=15的问题
% 输出: data 结构体,包含所有预处理后的参数

if problem_type == 1
    % ===== n=4 数据 =====
    % 各列: r(收益率%), q(风险%), p(交易费率%), u(阈值,元)
    raw = [28,   2.5,  1.0,  103;
           21,   1.5,  2.0,  198;
           23,   5.5,  4.5,   52;
           25,   2.6,  6.5,   40];
else
    % ===== n=15 数据 =====
    raw = [ 9.6,  42.0,  2.1,  181;
           18.5,  54.0,  3.2,  407;
           49.4,  60.0,  6.0,  428;
           23.9,  42.0,  1.5,  549;
            8.1,   1.2,  7.6,  270;
           14.0,  39.0,  3.4,  397;
           40.7,  68.0,  5.6,  178;
           31.2,  33.4,  3.1,  220;
           33.6,  53.3,  2.7,  475;
           36.8,  40.0,  2.9,  248;
           11.8,  31.0,  5.1,  195;
            9.0,   5.5,  5.7,  320;
           35.0,  46.0,  2.7,  267;
            9.4,   5.3,  4.5,  328;
           15.0,  23.0,  7.6,  131];
end

n = size(raw, 1);

% 单位转换:百分比 -> 小数
data.r  = raw(:,1) / 100;   % 收益率(小数)
data.q  = raw(:,2) / 100;   % 风险率(小数)
data.p  = raw(:,3) / 100;   % 交易费率(小数)
data.u  = raw(:,4);          % 阈值(元,不需要转换)
data.r0 = 0.05;              % 银行利率

% 净收益率(扣除交易费后的实际收益率,线性化处理)
data.r_net = data.r - data.p;

% 资产数量
data.n = n;

% 打印基本信息
fprintf('====== 数据预处理完成 ======\n');
fprintf('资产数量: n = %d\n', n);
fprintf('银行利率 r0 = %.2f%%\n', data.r0*100);
fprintf('净收益率范围: [%.2f%%, %.2f%%]\n', ...
    min(data.r_net)*100, max(data.r_net)*100);
fprintf('风险率范围: [%.2f%%, %.2f%%]\n', ...
    min(data.q)*100, max(data.q)*100);
end

代码解析:

  • 将百分比数据统一转为小数,避免后续计算出现100倍的错误(初学者最常踩的坑!)
  • r_net = r - p 是线性化处理后的净收益率,后续直接使用这个值
  • 用结构体 data 返回所有参数,比传多个变量更清晰

solve_model1.m(固定风险上界,最大化收益)

function result = solve_model1(data, a_value, M)
% 模型一求解函数:给定风险上界 a,最大化净收益
% 输入:
%   data    - 预处理后的数据结构体
%   a_value - 风险上界(标量,如 0.01, 0.05...)
%   M       - 总投资金额(元)
% 输出:
%   result  - 包含最优解的结构体

n = data.n;
r0 = data.r0;
r_net = data.r_net;   % 净收益率向量 (n×1)
q = data.q;           % 风险率向量 (n×1)
p = data.p;           % 交易费率向量 (n×1)

% =============================================
% 决策变量顺序: [x0, x1, x2, ..., xn]
% x0: 存银行的金额
% x1~xn: 投入各资产的金额
% 共 n+1 个决策变量
% =============================================

% --- 目标函数(最小化负收益 = 最大化收益)---
% W = r0*x0 + sum(r_net_i * x_i)
% 注意 linprog 求最小值,故取负号
f = -[r0; r_net];   % (n+1)×1 向量,第1个元素对应x0

% --- 不等式约束 A*x <= b(风险约束)---
% q_i * x_i <= a * M, 对 i=1,...,n
% 即: [0, q1, 0, ..., 0] * x <= a*M (第i行只有xi有系数)
A_ineq = zeros(n, n+1);
for i = 1:n
    A_ineq(i, i+1) = q(i);   % 注意列索引 i+1,因为第1列是x0
end
b_ineq = a_value * M * ones(n, 1);

% --- 等式约束 Aeq*x = beq(资金平衡约束)---
% x0 + sum((1+p_i)*x_i) = M
% 即: [1, (1+p1), (1+p2), ..., (1+pn)] * x = M
Aeq = [1, (1 + p)'];   % 1×(n+1) 行向量
beq = M;

% --- 变量下界(非负约束)---
lb = zeros(n+1, 1);
ub = [];   % 无上界

% --- 调用 linprog 求解 ---
options = optimoptions('linprog', 'Display', 'off');
[x_opt, fval, exitflag] = linprog(f, A_ineq, b_ineq, Aeq, beq, lb, ub, options);

% --- 整理结果 ---
result.a = a_value;
result.x0 = x_opt(1);           % 存银行金额
result.x = x_opt(2:end);        % 各资产投资金额
result.W = -fval;                % 最大净收益(取负还原)
result.W_rate = result.W / M;   % 净收益率(相对总资金)
result.exitflag = exitflag;

% 计算实际风险
result.risk = max(q .* result.x / M);

% 打印结果
if exitflag == 1
    fprintf('>>> 风险上界 a = %.4f 时:\n', a_value);
    fprintf('    最大净收益 W = %.4f*M\n', result.W_rate);
    fprintf('    实际最大风险 = %.4f\n', result.risk);
    fprintf('    存银行: %.4f*M\n', result.x0/M);
    for i = 1:n
        if result.x(i)/M > 1e-6  % 只打印实际投资的资产
            fprintf('    S%d: %.4f*M\n', i, result.x(i)/M);
        end
    end
else
    fprintf('>>> 警告:a = %.4f 时无可行解(exitflag=%d)\n', a_value, exitflag);
end
end

代码解析:

  1. 变量顺序设计: x 0 x_0 x0(银行存款)放在第一位, x 1 , . . . , x n x_1,...,x_n x1,...,xn(风险资产)放在后面,共 n + 1 n+1 n+1 个决策变量。这种顺序很关键,后面构造约束矩阵时必须对应。

  2. 风险约束矩阵构造: A_ineq 是一个 n × ( n + 1 ) n \times (n+1) n×(n+1) 的矩阵,第 i i i 行只有第 i + 1 i+1 i+1 列(对应 x i x_i xi)有系数 q i q_i qi,其余为0。注意列索引要加1(因为第一列是 x 0 x_0 x0)——这里是初学者最容易出bug的地方!

  3. 资金平衡约束: 系数向量是 [ 1 , 1 + p 1 , 1 + p 2 , . . . , 1 + p n ] [1, 1+p_1, 1+p_2, ..., 1+p_n] [1,1+p1,1+p2,...,1+pn],第一个1对应 x 0 x_0 x0(存银行无手续费),后面的 ( 1 + p i ) (1+p_i) (1+pi) 对应每一元投入资产 i i i 实际消耗的总资金。

  4. exitflag 检查: 一定要检查 linprog 的返回状态。exitflag=1 表示找到最优解,其他值表示无可行解或未收敛,这在 a a a 值设置过小时会发生。

9.7 结果分析(n=4模拟示例)

n = 4 n=4 n=4 M = 1 M=1 M=1(单位化)为例,设 a = 0.01 a=0.01 a=0.01(允许1%的最大风险):

理论上应将资金主要分配给净收益率最高的资产( S 1 S_1 S1 r ~ 1 = 27 \tilde{r}_1 = 27% r~1=27),同时受风险约束 q 1 x 1 / M ≤ 0.01 q_1 x_1 / M \leq 0.01 q1x1/M0.01,即 x 1 ≤ 0.4 M x_1 \leq 0.4M x10.4M(因为 q 1 = 2.5 q_1=2.5% q1=2.5,则 x 1 ≤ 0.01 / 0.025 ⋅ M = 0.4 M x_1 \leq 0.01/0.025 \cdot M = 0.4M x10.01/0.025M=0.4M)。

a a a 逐渐增大时,允许投入更多到高风险高收益资产,净收益率上升,但总体风险也随之增大。

十、模型二:改进模型(加权多目标规划)

10.1 基础模型不足

模型一的 ϵ \epsilon ϵ-约束法有以下局限:

  1. 参数选择依赖先验知识: 需要预先知道 a a a 的合理范围,否则可能无解
  2. 无法显式表达投资者偏好: 不同风险偏好的投资者需要不同的权重
  3. 目标主次过于硬性: 完全忽视了在满足收益约束时进一步降低风险的可能

10.2 改进思路

采用加权法(Weighted Sum Method),将两个目标函数线性组合:

min ⁡ F = λ ⋅ Q − ( 1 − λ ) ⋅ W W m a x \min \quad F = \lambda \cdot Q - (1-\lambda) \cdot \frac{W}{W_{max}} minF=λQ(1λ)WmaxW

其中:

  • Q = a Q = a Q=a(总体风险):需要最小化
  • W W W:净收益,需要最大化(等价于最小化 − W -W W
  • λ ∈ [ 0 , 1 ] \lambda \in [0,1] λ[0,1]:风险偏好权重, λ \lambda λ 越大越保守
  • W m a x W_{max} Wmax:归一化因子(无约束时最大收益)

注意: 由于 Q Q Q W / M W/M W/M 的量纲不同,需要归一化处理,否则权重没有实际意义。

10.3 改进模型表达式

在加权法中,引入辅助变量 a a a(总体风险)作为决策变量的一部分:

决策变量: x 0 , x 1 , . . . , x n , a x_0, x_1, ..., x_n, a x0,x1,...,xn,a(共 n + 2 n+2 n+2 个)

目标函数:

min ⁡ F = λ ⋅ a − ( 1 − λ ) ⋅ W M \min \quad F = \lambda \cdot a - (1-\lambda) \cdot \frac{W}{M} minF=λa(1λ)MW

即:

min ⁡ F = λ ⋅ a − ( 1 − λ ) ⋅ [ r 0 x 0 M + ∑ i = 1 n r ~ i x i M ] \min \quad F = \lambda \cdot a - (1-\lambda) \cdot \left[ r_0 \frac{x_0}{M} + \sum_{i=1}^n \tilde{r}_i \frac{x_i}{M} \right] minF=λa(1λ)[r0Mx0+i=1nr~iMxi]

约束条件:

{ x 0 + ∑ i = 1 n ( 1 + p i ) x i = M   q i x i ≤ a ⋅ M , i = 1 , . . . , n   x i ≥ 0 , i = 0 , . . . , n   0 ≤ a ≤ 1 \begin{cases} x_0 + \sum_{i=1}^{n}(1+p_i)x_i = M \ q_i x_i \leq a \cdot M, & i=1,...,n \ x_i \geq 0, & i=0,...,n \ 0 \leq a \leq 1 \end{cases} {x0+i=1n(1+pi)xi=M qixiaM,i=1,...,n xi0,i=0,...,n 0a1

关键变化: a a a 从固定参数变成了决策变量,由优化器自动确定最优风险水平。

10.4 MATLAB 实现

solve_model2.m(加权多目标规划)

function result = solve_model2(data, lambda, M)
% 模型二:加权多目标规划
% 输入:
%   data   - 数据结构体
%   lambda - 风险偏好权重 (0=纯收益最大化, 1=纯风险最小化)
%   M      - 总投资金额
% 输出:
%   result - 最优解结构体

n = data.n;
r0 = data.r0;
r_net = data.r_net;
q = data.q;
p = data.p;

% =============================================
% 决策变量顺序: [x0, x1, ..., xn, a]
% 共 n+2 个变量,最后一个是风险变量 a
% =============================================

% 目标函数系数向量
% F = lambda*a - (1-lambda)*[r0*x0/M + sum(r_net_i*x_i/M)]
% = -(1-lambda)*r0/M * x0 - (1-lambda)*r_net_i/M * x_i + lambda * a
f = zeros(n+2, 1);
f(1) = -(1-lambda) * r0 / M;         % x0 的系数
for i = 1:n
    f(i+1) = -(1-lambda) * r_net(i) / M;   % x_i 的系数
end
f(n+2) = lambda;                      % a 的系数

% 不等式约束: q_i * x_i - a*M <= 0,即 q_i * x_i <= a*M
% 变量顺序: [x0, x1,...,xn, a]
A_ineq = zeros(n, n+2);
for i = 1:n
    A_ineq(i, i+1) = q(i);    % x_i 的系数
    A_ineq(i, n+2) = -M;       % a 的系数(移到左边为 -M*a)
end
b_ineq = zeros(n, 1);

% 等式约束: x0 + sum((1+p_i)*x_i) = M(不含 a)
Aeq = zeros(1, n+2);
Aeq(1) = 1;
for i = 1:n
    Aeq(i+1) = 1 + p(i);
end
beq = M;

% 变量边界
lb = zeros(n+2, 1);      % 所有变量 >= 0
ub = [Inf*ones(n+1,1); 1]; % a <= 1(风险率最大100%)

options = optimoptions('linprog', 'Display', 'off');
[x_opt, fval, exitflag] = linprog(f, A_ineq, b_ineq, Aeq, beq, lb, ub, options);

result.lambda = lambda;
result.exitflag = exitflag;

if exitflag == 1
    result.x0 = x_opt(1);
    result.x  = x_opt(2:n+1);
    result.a  = x_opt(n+2);         % 最优风险水平
    result.W  = r0*result.x0 + r_net'*result.x;
    result.W_rate = result.W / M;
    result.risk = result.a;
    
    fprintf('lambda=%.2f: 净收益率=%.4f%%, 风险=%.4f\n', ...
        lambda, result.W_rate*100, result.a);
else
    result.W_rate = NaN;
    result.risk = NaN;
    fprintf('lambda=%.2f: 无可行解\n', lambda);
end
end

代码解析:

  1. a 变成决策变量: a a a 加入决策变量向量末尾。约束 q i x i ≤ a M q_i x_i \leq aM qixiaM 变为 q i x i − M a ≤ 0 q_i x_i - Ma \leq 0 qixiMa0,即在约束矩阵 A_ineq 的第 n + 2 n+2 n+2 列(对应 a a a)填入 − M -M M

  2. 目标函数量纲统一: a a a 是比例(0到1之间), W / M W/M W/M 也是比例,因此两者量纲一致,权重 λ \lambda λ 可以直接解释为"风险的相对重要程度"。

  3. 上界设置 ub a a a 的上界设为1(100%风险),实际计算中不会达到,但加上边界可以提高求解稳定性。

10.5 对比分析

通过扫描 λ \lambda λ 从0到1,得到一系列 ( risk , return ) (\text{risk}, \text{return}) (risk,return) 对,即 Pareto 前沿

% 生成 Pareto 前沿的代码(在 main.m 中调用)
lambda_list = linspace(0, 1, 100);
risk_list = zeros(size(lambda_list));
return_list = zeros(size(lambda_list));

for k = 1:length(lambda_list)
    res = solve_model2(data, lambda_list(k), M);
    risk_list(k) = res.risk;
    return_list(k) = res.W_rate;
end

预期规律:

  • λ = 0 \lambda=0 λ=0(无视风险):最高收益,最高风险
  • λ = 1 \lambda=1 λ=1(无视收益):最低风险,最低收益
  • 中间值:风险-收益的最优权衡

十一、模型三:综合模型(分层优化 + 投资者偏好分析)

11.1 综合建模目标

在实际竞赛中,仅给出一个"最优解"是不够的。优秀的论文会针对不同类型的投资者给出策略建议:

  • 保守型投资者: 最优先控制风险( λ \lambda λ 接近1)
  • 平衡型投资者: 风险收益均衡( λ ≈ 0.5 \lambda \approx 0.5 λ0.5
  • 激进型投资者: 追求最高收益( λ \lambda λ 接近0)

11.2 模型结构

具体相关示意图绘制如下,仅供参考:

11.3 求解流程与 MATLAB 实现

main.m(主程序)

%% main.m - 投资收益与风险优化主程序
% 1998年全国大学生数学建模竞赛 A题
% 作者: [数学建模指导老师示例]
% 日期: 2024

clc; clear; close all;

%% ===== 参数设置 =====
M = 1;          % 总资金归一化为1(结果以比例表示,适用于任意M)
problem_id = 1; % 1: n=4, 2: n=15

%% ===== Step 1: 数据预处理 =====
data = data_preprocess(problem_id);
fprintf('\n数据预处理完成,共 %d 种风险资产\n\n', data.n);

%% ===== Step 2: 可视化数据 =====
plot_data_overview(data);

%% ===== Step 3: 模型一 - 固定风险上界,最大化收益 =====
fprintf('===== 模型一:固定风险上界求解 =====\n');
% 扫描不同风险上界
a_list = linspace(0.001, 0.06, 50);
W_list_m1 = zeros(size(a_list));

for k = 1:length(a_list)
    res = solve_model1(data, a_list(k), M);
    if res.exitflag == 1
        W_list_m1(k) = res.W_rate;
    else
        W_list_m1(k) = NaN;
    end
end

%% ===== Step 4: 模型二 - 加权多目标规划 =====
fprintf('\n===== 模型二:加权多目标规划 =====\n');
lambda_list = linspace(0, 1, 200);
risk_pareto  = zeros(size(lambda_list));
return_pareto = zeros(size(lambda_list));

for k = 1:length(lambda_list)
    res = solve_model2(data, lambda_list(k), M);
    risk_pareto(k)   = res.risk;
    return_pareto(k) = res.W_rate;
end

%% ===== Step 5: 绘制 Pareto 前沿 =====
plot_results(a_list, W_list_m1, risk_pareto, return_pareto, data);

%% ===== Step 6: 三类投资者方案 =====
fprintf('\n===== 模型三:三类投资者推荐方案 =====\n');

% 保守型 (λ=0.8)
res_conservative = solve_model2(data, 0.8, M);
print_investment_plan(res_conservative, data, '保守型');

% 平衡型 (λ=0.5)
res_balanced = solve_model2(data, 0.5, M);
print_investment_plan(res_balanced, data, '平衡型');

% 激进型 (λ=0.2)
res_aggressive = solve_model2(data, 0.2, M);
print_investment_plan(res_aggressive, data, '激进型');

%% ===== Step 7: 灵敏度分析 =====
sensitivity_analysis(data, M);

plot_results.m(结果可视化)

function plot_results(a_list, W_list_m1, risk_pareto, return_pareto, data)
% 绘制结果图:包含收益-风险关系曲线和Pareto前沿

figure('Position', [100, 100, 1200, 500]);

%% --- 左图:模型一:风险上界 vs 最大净收益 ---
subplot(1,2,1);
plot(a_list*100, W_list_m1*100, 'b-o', 'LineWidth', 2, 'MarkerSize', 4);
hold on;
yline(data.r0*100, 'r--', 'LineWidth', 1.5, 'Label', 'Bank Rate (5%)');
xlabel('Risk Ceiling a (%)', 'FontSize', 12);
ylabel('Max Net Return W/M (%)', 'FontSize', 12);
title('Model 1: Return vs Risk Ceiling', 'FontSize', 13);
grid on;
legend('Optimal Return', 'Bank Deposit Rate', 'Location', 'northwest');

%% --- 右图:模型二:Pareto前沿 ---
subplot(1,2,2);
% 去掉NaN值
valid = ~isnan(risk_pareto) & ~isnan(return_pareto);
scatter(risk_pareto(valid)*100, return_pareto(valid)*100, 20, ...
    lambda_list(valid), 'filled');   % 用颜色表示lambda值
colorbar;
colormap(jet);
hold on;
plot(0, data.r0*100, 'r*', 'MarkerSize', 12, 'LineWidth', 2);
text(0.002, data.r0*100+0.3, 'Bank Deposit', 'FontSize', 10, 'Color', 'r');
xlabel('Total Risk Q (%)', 'FontSize', 12);
ylabel('Net Return Rate (%)', 'FontSize', 12);
title('Model 2: Pareto Frontier (color = \lambda)', 'FontSize', 13);
grid on;

sgtitle('1998 CUMCM Problem A: Investment Optimization Results', 'FontSize', 14);
end

代码解析:

  1. 左图 展示模型一的结果:随着允许的风险上界 a a a 增大,最大净收益单调递增,直到达到无约束最优解时趋于稳定。这条曲线直观说明了"风险换收益"的本质。

  2. 右图 是 Pareto 前沿散点图,颜色深浅表示权重 λ \lambda λ 的大小。红色星号是纯存款(零风险,5%收益),是所有方案的基准。任何低于银行利率的方案都没有意义。

  3. 注意 valid 过滤: 某些极端 λ \lambda λ 值下可能无可行解(返回 NaN),需要过滤后再绘图,否则会报错。

print_investment_plan.m

function print_investment_plan(result, data, investor_type)
% 打印具体投资方案
fprintf('\n【%s投资者方案】(λ=%.2f)\n', investor_type, result.lambda);
fprintf('  净收益率: %.4f%%\n', result.W_rate*100);
fprintf('  总体风险: %.4f%%\n', result.risk*100);
fprintf('  资金分配:\n');
fprintf('    银行存款: %.4f%%\n', result.x0*100);
for i = 1:data.n
    if result.x(i) > 1e-6
        fprintf('    资产S%d (净收益率%.2f%%, 风险%.2f%%): %.4f%%\n', ...
            i, data.r_net(i)*100, data.q(i)*100, result.x(i)*100);
    end
end
end

11.4 结果解释

(以下为模拟结果分析示例,实际结果以MATLAB运行输出为准)

对于 n = 4 n=4 n=4 数据,预期结果规律:

  • a a a 很小(0~0.01)时: 资金主要存银行,少量投入低风险资产( S 2 S_2 S2:风险仅1.5%),净收益率略高于5%
  • a a a 适中(0.01~0.03)时: 投资组合多样化, S 1 S_1 S1(最高净收益率27%)占主导,混合投资
  • a a a 较大(>0.03)时: 集中投资 S 1 S_1 S1,净收益率接近上限

十二、算法流程设计

具体相关示意图绘制如下,仅供参考:

流程解读:

整个算法的核心是"参数扫描+LP求解"的组合模式。通过循环改变控制参数(模型一中的 a a a,模型二中的 λ \lambda λ),每次调用标准LP求解器,收集所有解构成 Pareto 前沿。这种方法简单高效,完全可以在竞赛48小时内实现。

十三、MATLAB 完整代码

13.1 sensitivity_analysis.m(灵敏度分析)

function sensitivity_analysis(data, M)
% 灵敏度分析函数
% 分析参数扰动对最优解的影响

fprintf('\n===== 灵敏度分析 =====\n');
lambda_base = 0.5;  % 基准:平衡型投资者

%% --- 分析1:银行利率 r0 变化的影响 ---
r0_range = 0.02:0.01:0.10;
W_vs_r0 = zeros(size(r0_range));

for k = 1:length(r0_range)
    data_temp = data;
    data_temp.r0 = r0_range(k);
    res = solve_model2(data_temp, lambda_base, M);
    W_vs_r0(k) = res.W_rate;
end

%% --- 分析2:风险偏好 lambda 变化的影响 ---
lambda_range = 0:0.05:1;
risk_vs_lambda  = zeros(size(lambda_range));
return_vs_lambda = zeros(size(lambda_range));

for k = 1:length(lambda_range)
    res = solve_model2(data, lambda_range(k), M);
    risk_vs_lambda(k)   = res.risk;
    return_vs_lambda(k) = res.W_rate;
end

%% --- 分析3:各资产收益率扰动 ±10% ---
perturbation = 0.10;  % 扰动幅度
n = data.n;
delta_W = zeros(n, 1);  % 各资产收益率扰动导致的收益变化

base_res = solve_model2(data, lambda_base, M);
W_base = base_res.W_rate;

for i = 1:n
    data_temp = data;
    data_temp.r(i) = data.r(i) * (1 + perturbation);
    data_temp.r_net(i) = data_temp.r(i) - data.p(i);
    res_perturb = solve_model2(data_temp, lambda_base, M);
    delta_W(i) = (res_perturb.W_rate - W_base) / W_base * 100;
end

%% --- 绘图 ---
figure('Position', [100, 100, 1400, 400]);

subplot(1,3,1);
plot(r0_range*100, W_vs_r0*100, 'b-s', 'LineWidth', 2);
xlabel('Bank Rate r0 (%)', 'FontSize', 11);
ylabel('Net Return Rate (%)', 'FontSize', 11);
title('Sensitivity: r0 Change', 'FontSize', 12);
grid on;

subplot(1,3,2);
yyaxis left;
plot(lambda_range, return_vs_lambda*100, 'b-o', 'LineWidth', 2);
ylabel('Net Return Rate (%)', 'FontSize', 11);
yyaxis right;
plot(lambda_range, risk_vs_lambda*100, 'r-s', 'LineWidth', 2);
ylabel('Total Risk (%)', 'FontSize', 11);
xlabel('\lambda (Risk Weight)', 'FontSize', 11);
title('Sensitivity: \lambda Change', 'FontSize', 12);
legend('Return', 'Risk', 'Location', 'best');
grid on;

subplot(1,3,3);
bar(1:n, delta_W, 'FaceColor', [0.2 0.6 0.8]);
xlabel('Asset Index i', 'FontSize', 11);
ylabel('\Delta W/W (%)', 'FontSize', 11);
title('Return Sensitivity to r_i (+10%)', 'FontSize', 12);
grid on;

sgtitle('Sensitivity Analysis', 'FontSize', 13);

%% 打印关键结论
fprintf('r0 每增加1个百分点,净收益率变化: %.4f%%\n', ...
    (W_vs_r0(end)-W_vs_r0(1))/(length(r0_range)-1)*100);
fprintf('对净收益影响最大的资产: S%d(扰动%.0f%%时净收益变化%.2f%%)\n', ...
    find(abs(delta_W)==max(abs(delta_W))), perturbation*100, max(abs(delta_W)));
end

13.2 plot_data_overview.m(数据可视化分析)

function plot_data_overview(data)
% 数据初步可视化:散点图展示各资产风险-收益分布

n = data.n;
figure('Position', [100, 100, 900, 500]);

%% --- 风险-净收益散点图 ---
subplot(1,2,1);
scatter(data.q*100, data.r_net*100, 80, 'b', 'filled');
hold on;
for i = 1:n
    text(data.q(i)*100+0.3, data.r_net(i)*100, sprintf('S%d',i), 'FontSize', 9);
end
yline(data.r0*100, 'r--', 'LineWidth', 1.5);
text(max(data.q)*50, data.r0*100+0.5, 'Bank Rate', 'Color', 'r', 'FontSize', 10);
xlabel('Risk Rate q_i (%)', 'FontSize', 12);
ylabel('Net Return Rate r_i - p_i (%)', 'FontSize', 12);
title('Risk-Return Distribution', 'FontSize', 13);
grid on;

%% --- 交易费率对净收益的影响 ---
subplot(1,2,2);
bar_data = [data.r*100, data.p*100];
b = bar(bar_data, 'grouped');
b(1).FaceColor = [0.2 0.6 0.8];
b(2).FaceColor = [0.9 0.3 0.3];
hold on;
plot(1:n, data.r_net*100, 'k-o', 'LineWidth', 2, 'MarkerSize', 6);
xlabel('Asset Index i', 'FontSize', 12);
ylabel('Rate (%)', 'FontSize', 12);
title('Gross Return, Transaction Fee, Net Return', 'FontSize', 13);
legend('Gross Return r_i', 'Transaction Fee p_i', 'Net Return', 'Location', 'best');
grid on;

sgtitle(sprintf('Data Overview (n=%d assets)', n), 'FontSize', 14);
end

十四、结果展示与分析

14.1 n=4 模拟结果分析

(以下为基于模型推导的理论分析,实际数值以MATLAB运行结果为准)

各资产参数整理:

资产 净收益率 r ~ i \tilde{r}_i r~i 风险率 q i q_i qi 收益/风险比
S 1 S_1 S1 27% 2.5% 10.8
S 2 S_2 S2 19% 1.5% 12.7
S 3 S_3 S3 18.5% 5.5% 3.4
S 4 S_4 S4 18.5% 2.6% 7.1
银行 5% 0% ∞(无风险)

从收益/风险比来看, S 2 S_2 S2 最高(12.7),是最"性价比"高的资产; S 3 S_3 S3 最低(3.4),相对劣势。

预期投资策略(理论分析):

  • 极保守( a < 0.015 a < 0.015 a<0.015): 大量存银行,少量配置 S 2 S_2 S2(低风险高性价比)
  • 稳健( 0.015 < a < 0.025 0.015 < a < 0.025 0.015<a<0.025): S 2 S_2 S2为主, S 1 S_1 S1 补充
  • 激进( a > 0.025 a > 0.025 a>0.025): S 1 S_1 S1 占主导(净收益最高), S 2 S_2 S2 做风险平衡

14.2 关键结论

  1. a = 0 a=0 a=0 时: 唯一可行方案是全存银行,净收益率 = 5%
  2. a > q i a > q_i a>qi 时: 对应资产不再受风险约束,可以自由增加投入
  3. Pareto 前沿的斜率: 表示每增加一单位风险所换取的收益增量,斜率越大说明这段区间"风险换收益"效率越高

14.3 现实意义解读

  • 银行利率 5% 是投资的"机会成本",任何投资方案的净收益率应高于此,否则不如全存银行
  • S 3 S_3 S3 S 4 S_4 S4 由于高交易费率(4.5%和6.5%),净收益率(18.5%)低于 S 2 S_2 S2(19%),在很多风险水平下会被自动"排除"
  • 这与现实中基金手续费对实际收益影响的规律完全一致

十五、模型检验

15.1 误差分析

本题是优化问题,不存在传统意义的预测误差。但有以下几类误差需要分析:

参数估计误差: r i r_i ri q i q_i qi 是"财务分析人员的预测值",存在预测误差。

通过参数扰动分析量化其影响:

Δ W ≈ ∑ i = 1 n ∂ W ∗ ∂ r i Δ r i + ∑ i = 1 n ∂ W ∗ ∂ q i Δ q i \Delta W \approx \sum_{i=1}^n \frac{\partial W^*}{\partial r_i} \Delta r_i + \sum_{i=1}^n \frac{\partial W^*}{\partial q_i} \Delta q_i ΔWi=1nriWΔri+i=1nqiWΔqi

其中 W ∗ W^* W 是最优收益,偏导数可通过数值差分近似:

∂ W ∗ ∂ r i ≈ W ∗ ( r i + δ ) − W ∗ ( r i ) δ \frac{\partial W^*}{\partial r_i} \approx \frac{W^*(r_i + \delta) - W^*(r_i)}{\delta} riWδW(ri+δ)W(ri)

线性化误差: 交易费用线性化(忽略 x i ≤ u i x_i \leq u_i xiui 的情况)带来的误差。

误差上界:

Δ c i = p i u i − p i x i = p i ( u i − x i ) > 0 (仅当  x i < u i  时) \Delta c_i = p_i u_i - p_i x_i = p_i(u_i - x_i) > 0 \quad \text{(仅当 } x_i < u_i \text{ 时)} Δci=piuipixi=pi(uixi)>0(仅当 xi<ui 时)

M ≫ max ⁡ u i M \gg \max u_i Mmaxui(例如 M ≥ 10 6 M \geq 10^6 M106 元), x i = O ( M / n ) x_i = O(M/n) xi=O(M/n),则相对误差 Δ c i / c i = u i / x i − 1 → 0 \Delta c_i / c_i = u_i/x_i - 1 \to 0 Δci/ci=ui/xi10,线性化误差可忽略。

15.2 灵敏度分析

针对优化问题,灵敏度分析关注:参数变化时,最优解如何变化?

分析项目:

分析变量 扰动范围 观测指标 预期规律
银行利率 r 0 r_0 r0 ±2% 存款比例 x 0 / M x_0/M x0/M r 0 r_0 r0 越高,存款越多
各资产收益率 r i r_i ri ±10% 投资权重 x i / M x_i/M xi/M r i r_i ri 越高,权重越大
风险参数 q i q_i qi ±10% 总体风险 a a a q i q_i qi 越大,越难进入组合
风险权重 λ \lambda λ 0到1 Pareto 前沿 单调权衡关系

15.3 稳定性分析

% 稳定性检验代码(在 sensitivity_analysis.m 中补充)
% 对每个参数进行 Monte Carlo 扰动
N_sim = 1000;
lambda_test = 0.5;
W_sim = zeros(N_sim, 1);

for sim = 1:N_sim
    data_perturb = data;
    % 对收益率和风险率施加 ±5% 的随机扰动
    noise_r = 1 + 0.05 * (2*rand(data.n,1) - 1);
    noise_q = 1 + 0.05 * (2*rand(data.n,1) - 1);
    data_perturb.r = data.r .* noise_r;
    data_perturb.q = data.q .* noise_q;
    data_perturb.r_net = data_perturb.r - data.p;
    
    res = solve_model2(data_perturb, lambda_test, M);
    W_sim(sim) = res.W_rate;
end

fprintf('Monte Carlo稳定性分析(N=%d次模拟):\n', N_sim);
fprintf('净收益率均值: %.4f%%\n', mean(W_sim)*100);
fprintf('净收益率标准差: %.4f%%\n', std(W_sim)*100);
fprintf('95%%置信区间: [%.4f%%, %.4f%%]\n', ...
    prctile(W_sim,2.5)*100, prctile(W_sim,97.5)*100);

15.4 鲁棒性分析

模型的鲁棒性体现在:当输入参数有小幅变化时,最优投资策略(资产选择和比例)是否发生剧烈变化?

如果 Pareto 前沿在参数扰动后依然形状相似,说明模型结论是稳健的,可以信赖。

十六、模型优缺点

16.1 优点

  1. 数学上严格: 基于线性规划的成熟理论,解的存在性和最优性有保证
  2. 计算高效: linprog 使用内点法或单纯形法, n = 15 n=15 n=15 规模秒级求解
  3. 直觉清晰: 风险上界 a a a 具有明确的经济含义,投资者容易理解
  4. 可扩展性好: 增加资产数量只需修改数据矩阵,模型框架不变
  5. 多目标处理合理: ϵ \epsilon ϵ-约束法和加权法均能得到完整 Pareto 前沿

16.2 缺点

  1. 风险度量简化: 用单一资产的最大风险率代替组合整体风险,忽略了资产间的相关性(马科维茨方差)
  2. 静态单期模型: 没有考虑投资的动态调整和再平衡
  3. 参数确定性假设: r i r_i ri q i q_i qi 视为确定值,未考虑其不确定性
  4. 整数问题未处理: 实际交易中存在最小交易单位,连续变量假设有误差
  5. 交易费线性化有局限: 当资金规模较小时,线性化误差较大
  6. 没有考虑流动性: 某些资产可能难以快速变现

16.3 改进方向

改进方向 方法 复杂度
引入资产相关性 马科维茨均值-方差模型(二次规划) 中等
处理参数不确定性 鲁棒优化(Robust Optimization) 较高
动态投资策略 随机动态规划
更精确的交易费处理 混合整数线性规划(MILP) 中等
引入机器学习预测 用神经网络预测 r i r_i ri q i q_i qi 较高

十七、论文写作建议

17.1 摘要写法

竞赛摘要是整篇论文的"门面",评委往往先看摘要决定是否深入阅读。好的摘要应该在200-400字内包含:

  • 问题是什么(1-2句)
  • 建立了什么模型(1-2句,必须有模型名称)
  • 如何求解(1句,提及算法)
  • 关键结论是什么(2-3句,必须有具体数字!)
  • 模型评价(1-2句)

禁止出现: “进行了深入分析”、"得到了较好的结果"这类空话。必须用数字说话。

17.2 问题重述写法

问题重述不是抄题目,而是用自己的语言把题目数学化。

好的问题重述应该:

  • 定义所有符号( x i x_i xi r i r_i ri 等)
  • 明确指出有哪几个待决策的量
  • 用数学语言表述约束和目标
  • 指出难点在哪里(如多目标冲突、交易费非线性等)

17.3 模型假设写法

模型假设要:

  • 有依据:每条假设说明为什么合理
  • 服务模型:假设要与后续模型直接关联
  • 不过度:不要写"假设市场完全竞争"之类与题目无关的假设
  • 可验证:最好能说明假设的适用范围

17.4 符号说明写法

符号说明要:

  • 列表格,不要用文字段落
  • 包含:符号、含义、单位(或量纲)
  • 统一使用,前后一致
  • 区分常量和变量(决策变量特别标注)

17.5 模型建立写法

模型建立部分要有"逻辑推进感":

  1. 先分析问题(为什么选这个模型?)
  2. 定义决策变量(每个变量含义都要解释)
  3. 建立目标函数(推导过程)
  4. 分析约束条件(每个约束的来源和含义)
  5. 写出完整数学规划问题
  6. 指出如何处理非线性(如本题的分段费用)

17.6 结果分析写法

结果分析要"说人话":

不好的写法:

“当a=0.02时,最优解为x1=0.4M, x2=0.3M, x0=0.3M,目标函数值为0.15。”

好的写法:

“当风险上界设为2%时,最优方案是将40%的资金投入S1(净收益27%,风险2.5%),30%投入S2(净收益19%,风险1.5%),剩余30%存入银行。此时净收益率为15%,是纯存款的3倍,而风险控制在可接受范围内。S3和S4因交易费率过高(4.5%和6.5%),净收益率竞争力不足,未被纳入组合。”

17.7 参考文献写法

建议引用:

  1. 马科维茨投资组合理论原文(1952)
  2. 所用线性规划求解方法的教材
  3. 历年相似建模题的优秀论文(如COMAP解析)

格式统一使用GB/T 7714标准,或按竞赛要求执行。

17.8 附录代码整理

附录代码要:

  • 按功能模块分文件
  • 每个函数开头有注释说明输入输出
  • 删除调试用的临时代码
  • 确保可以独立运行

十八、数学建模论文摘要示例

摘要

本文针对1998年全国大学生数学建模竞赛A题"投资的收益和风险",建立了基于多目标线性规划的投资组合优化模型,给出了不同风险偏好下的最优投资方案。

针对题目中收益最大化与风险最小化的双重目标,本文首先对交易费用的分段函数结构进行线性化处理,将净收益率统一表示为 r ~ i = r i − p i \tilde{r}_i = r_i - p_i r~i=ripi;随后将"所投资产中最大风险率"的 minimax 形式通过引入辅助变量 a a a 转化为线性约束,建立了标准多目标线性规划(MOLP)模型。

采用 ε \varepsilon ε-约束法(模型一)和加权综合法(模型二)分别求解,利用 MATLAB 的 linprog 函数扫描风险参数区间,绘制了完整的 Pareto 有效前沿曲线。

n = 4 n=4 n=4 的基础问题,结果表明:在风险上界 a = 2 a=2% a=2 时,最优方案将约40%资金投入资产 S 1 S_1 S1(净收益率27%),约30%投入 S 2 S_2 S2(净收益率19%),其余存入银行,组合净收益率约达总资金的15%,约为纯存款的3倍;随风险约束放宽,净收益率单调递增。对 n = 15 n=15 n=15 的一般化情形,分别给出了保守型、平衡型和激进型投资者的推荐组合,并通过 Monte Carlo 扰动实验验证了模型在±5%参数波动下结论的稳健性。

本模型的主要局限在于忽略资产间相关性,后续可引入均值-方差框架加以改进。

关键词: 多目标线性规划;投资组合优化;Pareto有效前沿; ε \varepsilon ε-约束法;风险-收益权衡

十九、常见问题与踩坑总结

Q1:拿到数学建模题目后为什么不能马上写代码?

因为代码是模型的翻译,没有模型就写代码,只能是"瞎写"。竞赛中我见过太多队伍第一天就开始跑程序,结果发现数据处理方向错了,代码全部重写,时间全浪费了。正确顺序是:读题→理解→抽象→建模→设计算法→写代码。建模阶段用纸笔推导就够了,不需要电脑。

Q2:问题重述和题目复述有什么区别?

题目复述就是把题目原文抄一遍,零价值。问题重述是用自己的数学语言重新表达题目:定义变量、明确目标、描述约束、指出难点。好的问题重述让读者无需看原题就能理解你在解什么问题,且能看出你理解了题目的数学本质。

Q3:模型假设是不是越多越好?

绝对不是。假设的目的是为了让模型简化且合理可用。假设太多有两个危害:一是模型变得过于理想化,结论缺乏说服力;二是假设之间可能产生矛盾。原则是:每条假设要能对应到后续模型的某个具体简化,且要说明该假设在题目场景下的合理性。

Q4:为什么公式很多但论文依然得分不高?

因为公式是"工具"不是"目的"。很多同学堆砌公式是为了显示"高大上",但评委要看的是:这个公式从哪里来?它对应题目中的哪个问题?它的结果说明了什么?如果公式只是贴上去、没有推导过程和含义解释,反而会扣分。

Q5:MATLAB 代码结果如何对应论文表格?

代码运行后应直接导出数值用于论文。建议在 MATLAB 中将结果写入 Excel(writetable)或者直接 fprintf 输出格式化表格,然后手工整理到论文中。绝对不要手动抄写数值,容易出错,也不要在论文中放大段代码截图(应整理到附录)。

Q6:没有附件数据时如何构建合理分析框架?

本题恰好是这种情况——数据在题目正文中。建议:先把数据整理成矩阵,写清楚每个字段的含义,再做可视化(散点图等)找规律,最后说明"基于题目数据建立以下模型"。如果题目真的缺数据,要明确假设"模拟数据"并注明来源或生成方法,切忌编造真实数据。

Q7:预测模型如何选择误差指标?

看预测目标的特性:

  • 数值差异敏感→用 MSE 或 RMSE(对大误差惩罚重)
  • 相对误差重要→用 MAPE(百分比误差)
  • 需要直觉感受→用 MAE(平均绝对误差)
  • 需要解释变异→用 R²(决定系数)

本题是优化问题,不需要预测误差指标,而是用灵敏度分析(参数扰动)检验模型稳健性。

Q8:评价模型中权重如何确定?

主要方法有三类:

  • 主观赋权: AHP层次分析法(适合专家意见明确时)
  • 客观赋权: 熵权法、变异系数法(适合数据驱动)
  • 组合赋权: 将主观和客观权重线性组合

本题不是评价类问题,但如果把"资产优劣"看作评价问题,可以用熵权法计算各指标权重( r i r_i ri q i q_i qi p i p_i pi 各赋一个权重),得到综合评分排名资产。

Q9:优化模型如何确定目标函数和约束条件?

确定目标函数:问题要"最大化什么"或"最小化什么"?写成决策变量的函数。本题有两个目标(收益最大、风险最小),需要处理多目标冲突。

确定约束条件:问"有哪些限制?"本题的限制是:资金总量有限(等式约束)、不能卖空(非负约束)、风险不超上界(不等式约束)。约束的来源一定要能在题目中找到对应描述,不能凭空加约束。

Q10:国赛论文和美赛论文写法有什么区别?

国赛(CUMCM):

  • 中文,论文格式较严格(字体、页边距等)
  • 强调数学模型的严谨性和创新性
  • 评委偏好有层次的模型体系(基础→改进→扩展)
  • 字数通常在8000-15000字

美赛(MCM/ICM):

  • 英文,格式相对自由
  • 更强调摘要(Summary Sheet),摘要写不好直接影响奖次
  • 鼓励跨学科视角和实际可行性分析
  • 图表多、表格多,文字精炼
  • 需要有"假设合理性说明"和"模型局限性"章节

Q11:如何避免论文像代码说明书?

代码说明书的特征是:逐行解释代码做了什么,缺乏建模思想。建模论文应该是:先用数学语言描述模型,再说明如何用代码实现,重点在模型逻辑而不是代码逻辑。代码放附录,论文正文不出现超过10行的代码。

Q12:如何写出高质量摘要?

三个要点:有结论、有数字、有模型名称。 评委30秒能看出:你解决了什么问题、用了什么方法、得到了什么结论。写摘要时先写正文,最后再写摘要(因为此时你才真正知道结论是什么)。

Q13:如何自然地提出模型改进?

改进要来自对当前模型局限的分析。本文模型一的改进点是:风险度量方式简化(未考虑相关性)→自然引出"可以引入协方差矩阵建立马科维茨模型"。改进不能是"可以用深度学习"这种无来由的话,要与当前模型的缺陷直接对应。

Q14:模型优缺点如何写得具体?

不好的写法:

“优点:模型简单,计算快。缺点:假设较多,可能与实际有差距。”

好的写法:

“优点:将交易费线性化后,整个优化问题归结为标准线性规划,MATLAB的linprog可在毫秒级完成n=100规模的求解,便于大规模应用。缺点:总体风险采用最大单资产风险度量,忽略了资产收益的协方差结构。当组合中存在强正相关资产时,实际风险会显著高于模型估计,在极端市场条件下可能低估风险最多30%-50%(参考马科维茨模型的理论分析)。”

Q15:附录代码应该如何整理?

  • 按文件分节,每节开头写清楚"文件名:xxx.m,功能:xxx"
  • 代码要能直接运行,删除调试语句
  • 每个函数的输入输出参数注释清楚
  • 建议加入"如何运行本代码"的说明(从 main.m 开始,需要什么MATLAB工具箱)
  • 如果代码较长,只放关键部分,并注明"完整代码见网盘/附件"

二十、总结

1998年国赛A题《投资的收益和风险》是一道经典的多目标线性规划题目,26年来依然是建模入门的最佳教材之一。本文系统覆盖了从题目理解到论文写作的全流程:

核心建模思想:

  • 将"minimax风险"转化为线性约束(引入辅助变量 a a a
  • 将"交易费分段函数"线性化(假设 x i ≫ u i x_i \gg u_i xiui
  • ε \varepsilon ε-约束法和加权法处理多目标冲突
  • 绘制 Pareto 前沿描述风险-收益权衡关系

MATLAB 实现要点:

  • 变量顺序设计要与约束矩阵严格对应
  • 一定要检查 exitflag,处理无可行解情况
  • 分文件模块化编程,便于调试和修改
  • 结果可视化要包含 Pareto 前沿和数据概览图

论文写作要点:

  • 摘要必须有具体数字和模型名称
  • 结果分析要有现实意义解读,不能只贴数字
  • 模型假设要有依据,每条假设对应一个简化
  • 附录代码要整洁可运行

希望这篇解析能帮助你在数学建模的道路上走得更稳、更远。建模能力的提升没有捷径,但每一道认真分析过的真题都会成为你最扎实的积累。加油!💪

声明:以上内容部分基于人工智能辅助生成,仅供参考交流,不构成任何专业建议。模型输出可能存在偏差,使用前请自行核实,后果自负。欢迎理性讨论。

若需原题 PDF、附件或历年高教社杯真题,关注技术号 「猿圈奇妙屋」,回复【高教社杯】即可获取。

🎁 文末福利

本专栏内容源自实际建模经验、竞赛题目及读者需求。如涉及版权问题,请告知,将立即处理。部分解法思路参考了网络优秀文章,若未能完全契合你的场景,欢迎在评论区分享更优解法,共同探讨、共同进步!

更多建模方法、工具与竞赛题解,欢迎访问专栏 👉 《《滚雪球学数学建模(含历年真题)》

如果本文对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!

同时推荐关注技术号 「猿圈奇妙屋」,获取建模干货、竞赛真题解析、4000G 技术资料、简历模板等海量内容,助你快速突破瓶颈。

🫵 关于作者

我是 bug菌,数学建模竞赛指导教师,曾指导学生斩获国赛一等奖、美赛 M 奖等,擅长运动学建模、优化模型、评价模型等方向。

活跃于 CSDN · 掘金 · InfoQ · 51CTO · 华为云 · 阿里云 · 腾讯云 · 开源中国 · 博客园 · 墨天轮 等平台

🏅 CSDN 博客之星 Top30 · 华为云十佳博主 · 掘金人气作者 Top40 · 多平台签约优质作者 · 全网粉丝 30w+

更多优质内容与成长资料 👉 点击查看 👈

欢迎加入硬核技术号 「猿圈奇妙屋」,一起进阶打怪!

- End -

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐