【数学建模】——数学规划模型
目录
一、线性规划(Linear Programming)
1.1 线性规划的基本概念
1.2 线性规划的图解法
模型建立:
二、整数规划(Integer Programming)
2.1 整数规划的基本概念
2.2 整数规划的求解方法
三、非线性规划(Nonlinear Programming)
3.1 非线性规划的基本概念
非线性规划的基本形式:
3.2 非线性规划的求解方法
四、动态规划(Dynamic Programming)
4.1 动态规划的基本概念
4.2 动态规划的求解步骤
实例题目:智能城市交通调度优化
背景
任务
要求
示例
参考代码
编辑
进一步学习和扩展
编辑
总结
专栏:数学建模学习笔记
数学规划是数学建模中的一个重要部分,它主要研究如何通过建立数学模型来解决优化问题。数学规划广泛应用于工程、经济、管理、物流等多个领域,帮助决策者在资源有限的情况下做出最优决策。数学规划包括线性规划、整数规划、非线性规划、动态规划等不同类型。
一、线性规划(Linear Programming)
1.1 线性规划的基本概念
线性规划是研究目标函数和约束条件均为线性关系的优化问题。线性规划模型由以下几个部分组成:
- 决策变量:表示需要确定的变量。
- 目标函数:表示需要优化(最大化或最小化)的函数。
- 约束条件:表示限制决策变量的条件。
一个典型的线性规划问题的数学表达形式为:
1.2 线性规划的图解法
图解法适用于变量较少(一般为两个变量)的线性规划问题,通过绘制约束条件的边界线并找到可行解区域,然后确定目标函数在该区域的最优解。
例子:假设某工厂生产两种产品,产品A和产品B。每种产品的利润分别为40元和30元。生产这两种产品需要消耗原材料和工作时间。已知资源和时间的限制如下:
- 每种产品A需要2单位原材料和3小时的工作时间。
- 每种产品B需要4单位原材料和1小时的工作时间。
- 每天最多有120单位的原材料和100小时的工作时间。
模型建立:
设 x1 为生产产品A的数量,x2 为生产产品B的数量,则:
通过绘制约束条件的直线,可以找到可行解区域,然后求出最优解。以下是Python代码生成的图表:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.font_manager import FontProperties# 设置中文字体
font = FontProperties(fname='C:/Windows/Fonts/simhei.ttf') # 这里的路径需要根据实际情况修改# 定义决策变量的范围
x = np.linspace(0, 50, 400)# 画出约束条件
y1 = (120 - 2*x) / 4
y2 = 100 - 3*x# 填充可行解区域
plt.fill_between(x, np.minimum(y1, y2), where=(y1>=0) & (y2>=0), color='gray', alpha=0.5)# 画出约束条件的直线
plt.plot(x, y1, label=r'$2x_1 + 4x_2 \leq 120$')
plt.plot(x, y2, label=r'$3x_1 + x_2 \leq 100$')# 设置坐标轴标签和图例
plt.xlabel(r'$x_1$', fontproperties=font)
plt.ylabel(r'$x_2$', fontproperties=font)
plt.xlim((0, 50))
plt.ylim((0, 50))
plt.legend(prop=font)plt.title('线性规划图解法', fontproperties=font)
plt.grid(True)
plt.show()
从图中可以看出,最优解位于可行解区域的顶点之一,通过计算可以得出最优解为:x1=20, x2=10,对应的最大利润为 Z=40×20+30×10=1100 元。
二、整数规划(Integer Programming)
2.1 整数规划的基本概念
整数规划是一种优化方法,其中决策变量必须取整数值。这种方法在需要离散决策的场景中非常有用,例如工厂生产中确定生产批次、员工排班、设备调度等。
整数规划可以分为纯整数规划和混合整数规划:
- 纯整数规划:所有决策变量都是整数。
- 混合整数规划:部分决策变量是整数,部分决策变量是连续的。
整数规划问题通常比线性规划问题复杂得多,因为整数约束使得问题的可行解空间变得离散和不规则。
2.2 整数规划的求解方法
整数规划的求解方法包括:
- 分枝定界法:通过构建搜索树逐步缩小可行解空间,找到最优解。
- 割平面法:通过在可行解空间中添加新的约束条件,逐步缩小可行解空间。
- 启发式算法:使用启发式方法寻找近似最优解,常用于大规模复杂问题。
例子:某工厂需要生产两种产品,每种产品的利润分别为50元和40元。每种产品的生产需要消耗原材料和机器时间,具体资源限制如下:
- 每种产品A需要1单位原材料和2小时机器时间。
- 每种产品B需要3单位原材料和1小时机器时间。
- 每天最多有10单位的原材料和12小时的机器时间。
- 需要的产品数量为整数。
模型建立:
设 x1 为生产产品A的数量,x2 为生产产品B的数量,则:
from scipy.optimize import linprog# 定义目标函数系数(注意这里是求最大化问题,所以目标函数系数取负)
c = [-50, -40]# 定义约束条件矩阵和约束条件向量
A = [[1, 3], [2, 1]]
b = [10, 12]# 定义变量取值范围
x_bounds = (0, None)
y_bounds = (0, None)# 求解线性规划问题
res = linprog(c, A_ub=A, b_ub=b, bounds=[x_bounds, y_bounds], method='highs')# 打印求解结果
print("Optimization Result:", res)# 检查求解结果是否成功
if res.success:# 手动调整为整数解optimal_solution = (3, 2)optimal_value = 50 * optimal_solution[0] + 40 * optimal_solution[1]# 打印最终结果print("Optimal Solution (Adjusted to Integers):", optimal_solution)print("Optimal Value:", optimal_value)
else:print("Optimization was not successful.")
上述代码使用SciPy库求解该整数规划问题。首先求解连续解,然后手动调整为整数解。通过计算可以得出最优解为:x1=3, x2=2,对应的最大利润为Z=50×3+40×2=230 元。
三、非线性规划(Nonlinear Programming)
3.1 非线性规划的基本概念
非线性规划是指目标函数或约束条件中至少有一个是非线性的优化问题。非线性规划问题在实际中非常常见,如生产规划、投资组合优化、资源分配等。
非线性规划的基本形式:
3.2 非线性规划的求解方法
求解非线性规划问题的方法包括:
- 梯度下降法:通过沿着目标函数的负梯度方向逐步迭代逼近最优解,适用于凸函数优化问题。
- 牛顿法:使用二阶导数信息加速收敛,适用于光滑函数优化问题。
- 内点法:通过引入障碍函数将原问题转换为一系列无约束优化问题逐步求解。
可以使用梯度下降法求解该非线性规划问题。以下是Python代码实现该问题的求解:
import numpy as np
from scipy.optimize import minimize# 定义目标函数
def objective(x):return -(4 * x[0]**2 + 2 * x[1]**2 - x[0] * x[1])# 定义约束条件
def constraint1(x):return 10 - (x[0] + x[1])# 定义变量取值范围
b = (0.0, None)
bounds = [b, b]# 定义初始解
x0 = [5, 5]# 定义约束
con1 = {'type': 'ineq', 'fun': constraint1}
cons = [con1]# 求解非线性规划问题
solution = minimize(objective, x0, method='SLSQP', bounds=bounds, constraints=cons)# 获取最优解和最优值
optimal_solution = solution.x
optimal_value = -solution.fun# 打印结果
print("Optimal Solution (x1, x2):", optimal_solution)
print("Optimal Value (Z):", optimal_value)
上述代码使用SciPy库求解该非线性规划问题。通过计算可以得出最优解为:最优解为x1=10 和 x2=0,对应的最大利润为 Z≈400
四、动态规划(Dynamic Programming)
4.1 动态规划的基本概念
动态规划是一种用于解决多阶段决策问题的优化方法。通过将复杂问题分解为相互依赖的子问题逐步求解,最终获得最优解。
动态规划的基本思想是记住以前的计算结果,以避免重复计算。这种方法特别适用于有阶段性决策的多阶段优化问题。
4.2 动态规划的求解步骤
求解动态规划问题通常包括以下几个步骤:
- 确定阶段:将问题分解为多个阶段,每个阶段表示一个决策步骤。
- 定义状态和决策:状态表示在每个阶段的具体情况,决策表示在每个阶段的选择。
- 写出状态转移方程:表示从一个状态转移到另一个状态的关系。
- 确定边界条件:定义初始状态和结束状态。
- 递推求解:从初始状态开始逐步求解,直至最终状态。
例子:假设有一个投资项目,每年可以投资若干金额,每年的收益率不同。如何在有限的资金内最大化总收益?
模型建立:
可以使用动态规划方法逐步求解每年的最优投资策略。以下是Python代码实现该问题的求解:
import numpy as np# 定义收益函数
def profit(x, rate):return x * rate# 定义投资金额和收益率
investment = [0, 1, 2, 3, 4, 5]
rates = [0, 0.1, 0.2, 0.3, 0.4, 0.5]# 定义总资金限制
C = 5
n = len(rates)# 初始化收益表
dp = np.zeros((n, C + 1))# 动态规划求解
for i in range(1, n):for j in range(C + 1):if j >= investment[i]:dp[i][j] = max(dp[i-1][j], dp[i-1][j-investment[i]] + profit(investment[i], rates[i]))else:dp[i][j] = dp[i-1][j]# 打印收益表,便于调试
print("Dynamic Programming Table:")
print(dp)# 获取最大总收益
optimal_value = dp[n-1][C]print("Optimal Value:", optimal_value)
上述代码使用动态规划方法求解该投资问题。通过计算可以得出最大总收益为 2.5。
实例题目:智能城市交通调度优化
背景
在一个智能城市中,有多个交通枢纽(如公交车站、地铁站等),需要通过智能调度系统优化车辆的调度和线路安排,以提高乘客的出行效率和城市的交通管理水平。
任务
设计一个数学规划模型,用于优化智能城市的交通调度,目标是最大化乘客满意度并最小化运营成本。模型需要考虑以下因素:
- 不同交通枢纽之间的乘客需求。
- 车辆的容量限制。
- 运营成本,包括燃料成本、司机工资等。
- 高峰时段和非高峰时段的不同需求。
- 车辆调度的时间窗约束。
- 乘客等待时间和行程时间的约束。
要求
-
建立数学规划模型:
- 定义决策变量。
- 定义目标函数,考虑乘客满意度和运营成本的平衡。
- 定义约束条件,考虑车辆容量、时间窗、需求等。
-
求解模型:
- 使用线性规划、整数规划或非线性规划技术求解模型。
- 如果问题规模较大,可以使用动态规划或其他启发式算法求解。
-
分析和优化:
- 对求解结果进行分析,找出瓶颈和改进点。
- 提出优化建议,如增加车辆、优化线路等。
示例
假设有3个交通枢纽A、B、C,乘客需求如下:
- A到B的需求为100人/小时,A到C的需求为50人/小时,B到C的需求为70人/小时。
- 每辆公交车的容量为50人。
- 运营成本为每辆车每小时50元。
- 乘客的等待时间不能超过30分钟,行程时间不能超过1小时。
请根据上述信息建立模型并求解。
参考代码
以下是一个初步的代码框架,可以帮助你开始解决这个问题:
import numpy as np
from scipy.optimize import linprog# 定义交通枢纽和需求
hubs = ['A', 'B', 'C']
demand = {('A', 'B'): 100,('A', 'C'): 50,('B', 'C'): 70
}
capacity = 50
cost_per_vehicle = 50
max_wait_time = 30
max_travel_time = 60# 定义决策变量
# x[i, j] 表示从枢纽i到枢纽j的车辆数量
n = len(hubs)
x = np.zeros((n, n))# 定义目标函数
# 目标是最小化运营成本
c = [cost_per_vehicle] * (n * (n - 1))# 定义约束条件
A = []
b = []
for (i, j), d in demand.items():A.append([1 if (hubs.index(i), hubs.index(j)) == (k // n, k % n) else 0 for k in range(n * (n - 1))])b.append(np.ceil(d / capacity))# 求解线性规划问题
res = linprog(c, A_eq=A, b_eq=b, bounds=[(0, None)] * (n * (n - 1)), method='highs')# 获取最优解和最优值
optimal_solution = res.x
optimal_value = res.fun# 打印结果
print("Optimal Solution:", optimal_solution)
print("Optimal Cost:", optimal_value)
进一步学习和扩展
- 模型复杂化:考虑更多的枢纽、更复杂的需求模式以及不同类型的车辆(如电动公交车)。
- 动态规划:将问题扩展为动态规划问题,考虑时间序列上的需求变化。
- 多目标优化:除了成本和满意度,考虑其他目标如碳排放、能源消耗等。
总结
数学规划模型是解决优化问题的强大工具,通过建立数学模型,可以清晰地描述问题、分析问题并找到最优解。不同类型的数学规划模型适用于不同的问题类型,掌握这些基本概念和求解方法,可以有效地应用数学规划模型解决实际问题。
相关文章:
【数学建模】——数学规划模型
目录 一、线性规划(Linear Programming) 1.1 线性规划的基本概念 1.2 线性规划的图解法 模型建立: 二、整数规划(Integer Programming) 2.1 整数规划的基本概念 2.2 整数规划的求解方法 三、非线性规划&#x…...
卸载linux 磁盘的内容,磁盘占满
Linux清理磁盘 https://www.cnblogs.com/siyunianhua/p/17981758 当前文件夹下,数量 ls -l | grep "^-" | wc -l ls -lR | grep "^-" | wc -l 找超过100M的大文件 find / -type f -size 100M -exec ls -lh {} \; df -Th /var/lib/docker 查找…...
LeetCode-随机链表的复制
. - 力扣(LeetCode) 本题思路: 首先注意到随机链表含有random的指针,这个random指针指向是随机的;先一个一个节点的拷贝,并且把拷贝的节点放在拷贝对象的后面,再让拷贝节点的next指向原链表拷贝…...
axios 下载大文件时,展示下载进度的组件封装——js技能提升
之前面试的时候,有遇到一个问题:就是下载大文件的时候,如何得知下载进度,当时的回复是没有处理过。。。 现在想到了。axios中本身就有一个下载进度的方法,可以直接拿来使用。 下面记录一下处理步骤: 参考…...
Linux: network: device事件注册机制 chatGPT; notify
ChatGPT 在 Linux 内核中,有关网络设备(net-device)的事件注册机制,允许用户在网络设备的状态发生变化(例如设备被删除、添加或修改)时接收通知。这主要通过 netdev 事件通知机制实现。具体来说,内核提供了一组用于注册和处理网络设备事件的 API。 以下是一些关键组件…...
【ROS2】测试
为什么要进行自动化测试? 以下是我们应该进行自动化测试的许多重要原因之一: 您可以更快地对代码进行增量更新。ROS 有数百个包,具有许多相互依赖关系,因此很难预见一个小变化可能引起的问题。如果您的更改通过了单元测试…...
别卷模型,卷应用:从李彦宏的AI观点谈起
2024年7月4日,世界人工智能大会暨人工智能全球治理高级别会议在上海世博中心隆重召开。百度创始人、董事长兼首席执行官李彦宏在产业发展主论坛上的发言,引起了广泛关注。他提出:“大家不要卷模型,要卷应用!”这一观点…...
数据库(Database,简称DB)介绍
数据库(Database,简称DB)是信息技术领域中一个至关重要的组成部分,它按照数据结构来组织、存储和管理数据。以下是对数据库的详细介绍: 一、定义与基本概念 定义:数据库是按照数据结构来组织、存储和管理…...
Redis五种常用数据类型详解及使用场景
Redis 5 种基本数据类型 Redis 共有 5 种基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。 这 5 种数据类型…...
Postman API测试覆盖率:全面评估指南
📊 Postman API测试覆盖率:全面评估指南 在API测试中,测试覆盖率是一个关键指标,它衡量了测试用例对代码的覆盖程度。Postman提供了多种工具和方法来评估API测试覆盖率,帮助开发者和测试人员确保API的质量和稳定性。本…...
C++--find
find 在[first,last)区间找第一个等于val的元素。 template<class InputIterator, class T> InputIterator find(InputIterator first,//起始迭代器 InputIterator last, //结束迭代器 const T& val); //需要查找的值 源码剖析 template<class InputI…...
JavaWeb入门程序解析(Spring官方骨架、配置起步依赖、SpringBoot父工程、内嵌Tomcat)
3.3 入门程序解析 关于web开发的基础知识,我们可以告一段落了。下面呢,我们在基于今天的核心技术点SpringBoot快速入门案例进行分析。 3.3.1 Spring官方骨架 之前我们创建的SpringBoot入门案例,是基于Spring官方提供的骨架实现的。 Sprin…...
mysql命令练习
创建数据表grade: CREATE TABLE grade( id INT NOT NULL, sex CHAR(1), firstname VARCHAR(20) NOT NULL, lastname VARCHAR(20) NOT NULL, english FLOAT, math FLOAT, chinese FLOAT ); 向数据表grade中插…...
AI绘画Stable Diffusion 零基础入门 —AI 绘画原理与工具介绍,万字解析AI绘画的使用教程
大家好,我是设计师阿威 想要入门 AI 绘画,首先需要了解它的原理是什么样的。 其实很早就已经有人基于深度学习模型展开了对图像生成的研究了,但在那时,生成的图像分辨率和内容都非常抽象。 直到近两年,AI 产出的图像…...
jenkins添加ssh证书
1、生成ssh密匙:windows生成ssh密匙-CSDN博客 2、添加添加ssh凭证:jenkins路由地址为:/manage/credentials/store/system/domain/_/ 点击添加凭证 选择第二个,将生成的私匙 id_rsa 里边的内容赋值到密钥,id留空自动…...
C++--accumulate介绍
在C中,accumulate是一个用于对容器中的元素进行累加操作的函数模板,位于 头文件中。它允许你对容器(如vector或array)中的元素进行累加运算,并返回累加的结果。 源代码展示 template<class InputIterator, class …...
C++写一个线程池
C写一个线程池 文章目录 C写一个线程池设计思路测试数据的实现任务类的实现线程池类的实现线程池构造函数线程池入口函数队列中取任务添加任务函数线程池终止函数 源码 之前用C语言写了一个线程池,详情请见: C语言写一个线程池 这次换成C了!…...
【SASS/SCSS(一)】选择器
Sass 是一门高于 CSS 的元语言,它能用来清晰地、结构化地描述文件样式。 而SCSS是SASS引入的语法,是CSS的超集,所以所有CSS有效的使用在SCSS中都生效 一、回顾CSS选择器 通用选择器 *元素选择器类选择器,.classNameID选择器&am…...
详细解析Kafaka Streams中各个DSL操作符的用法
什么是DSL? 在Kafka Streams中,DSL(Domain Specific Language)指的是一组专门用于处理Kafka中数据流的高级抽象和操作符。这些操作符以声明性的方式定义了数据流的转换、聚合、连接等处理逻辑,使得开发者可以更加专注…...
C++中链表的底层迭代器实现
大家都知道在C的学习中迭代器是必不可少的,今天我们学习的是C中的链表的底层迭代器的实现,首先我们应该先知道链表的底层迭代器和顺序表的底层迭代器在实现上有什么区别,为什么顺序表的底层迭代器更加容易实现,而链表的底层迭代器…...
3.5、matlab打开显示保存点云文件(.ply/.pcd)以及经典点云模型数据
1、点云数据简介 点云数据是三维空间中由大量二维点坐标组成的数据集合。每个点代表空间中的一个坐标点,可以包含有关该点的颜色、法向量、强度值等额外信息。点云数据可以通过激光扫描、结构光扫描、摄像机捕捉等方式获取,广泛应用于计算机视觉、机器人…...
Qt-事件与信号
事件和信号的区别在于,事件通常是由窗口系统或应用程序产生的,信号则是Qt定义或用户自定义的。Qt为界面组件定义的信号往往通常是对事件的封装,如QPushButton的clicked()信号可以看做对QEvent::MouseButtonRelease类事件的封装。 在使用界面组…...
数据结构 day3
目录 思维导图: 学习内容: 1. 顺序表 1.1 概念 1.2 有关顺序表的操作 1.2.1 创建顺序表 1.2.2 顺序表判空和判断满 1.2.3 向顺序表中添加元素 1.2.4 遍历顺序表 1.2.5 顺序表按位置进行插入元素 1.2.6 顺序表任意位置删除元素 1.2.7 按值进…...
Kubernetes面试整理-如何进行滚动更新和回滚?
在 Kubernetes 中,滚动更新和回滚是管理应用程序版本的常用操作。滚动更新允许您逐步替换现有的 Pod 实例,以便在不中断服务的情况下部署新版本。回滚则是在新版本出现问题时恢复到之前的版本。 滚动更新 通过 Deployment 进行滚动更新 1. 创建一个 Deployment: 下面是一个…...
flutter ios打包 xcode报错module ‘xxx‘ not found
flutter ios打包 xcode报错module ‘xxx’ not found 如果已经在androidstudio中成功运行了flutter build ios --release。 那么可能是你使用xcode打开的是ios/Runner.xcodeproj文件。 你关掉xcode,重新打开ios/Runner.xcworkspace/文件。然后重新archiveÿ…...
LLM 构建Data Multi-Agents 赋能数据分析平台的实践之④:数据分析之三(数据展示)
概述 在先前探讨的文章中,我们构建了一个全面的数据测试体系,该体系遵循“数据获取—数据治理—数据分析”的流程。如何高效地构建数据可视化看板,以直观展现分析结果,正逐渐成为利用新兴技术提升效能的关键领域。伴随业务拓展、数…...
Elasticsearch 批量更新
Elasticsearch 批量更新 准备条件查询数据批量更新 准备条件 以下查询操作都基于索引crm_flow_info来操作,索引已经建过了,本文主要讲Elasticsearch批量更新指定字段语句,下面开始写更新语句执行更新啦! 查询数据 查询指定shif…...
【Pytorch笔记】张量
torch.Tensor() 是 PyTorch 库中用于创建张量的一个函数。在 PyTorch 中,张量是多维数组,它们可以存储在 CPU 或 GPU 上,并且支持自动求导,这使得它们非常适合进行深度学习和科学计算。 张量可以在Python list形式下通过 torch.T…...
查找json中指定节点的值,替换为指定的值
有时我们封装好的实体转化成的json字段的值和第三方要求的不一样,比如我们字段的值是字符串,我们需要使用int类型的值,就需要将这个键的值转化成int类型。 比如将以下 convulsionNumber字段中字符串的值“一次”替换为0 {"convulsionT…...
Android 14 开机时间优化措施
Android开机优化系列文档-CSDN博客 Android 14 开机时间优化措施汇总-CSDN博客Android 14 开机时间优化措施-CSDN博客根据systrace报告优化系统时需要关注的指标和优化策略-CSDN博客Android系统上常见的性能优化工具-CSDN博客Android上如何使用perfetto分析systrace-CSDN博客A…...
网站建设分类/郑州计算机培训机构哪个最好
下载地址:网盘下载内容简介编辑本书深入浅出地介绍了Visual Basic 6语言的基本概念和编程技术,包括对象、属性、方法、语句、函数、结构等基本问题,以及面向对象编程、数据库管理和网络编程等高级课题。全书共分为21章,系统地讨论…...
临安做企业网站的公司/网络营销策划书的结构
今天把博客程序部署到一台阿里云Windows主机上,通过浏览器访问时出现下面的错误: 创建 BlogConfigurationSettings 的配置节处理程序时出错: 拒绝访问临时目录。以其运行 XmlSerializer 的身份“IIS APPPOOL\www.cnblogs.com”没有足够的权限访问临时目录…...
哈尔滨营销网站建设/南城网站优化公司
今天我在学习《Python编程:从入门到实践》的时候,发一下一个问题,特此在此记录一下! Geany是一款简单的文本编辑器:它易于安装;让你能够直接运行几乎所有的程序(而无需通过终端来运行ÿ…...
做网站开发用哪种语言好/广告软文营销平台
思路: 1、通过filter向目标页面传递一个自定义的response对象 2.、在这个response对象中通过重写getOutputStream方法和getWriter方法使目标资源调用 该方法输出页面内容时,获得我们自定义的ServletOutputStream对象 3、在我们自己定义的ServletOutputSt…...
wordpress中文客服侧边栏qq/电商平台怎么做
create database test on primary -- 默认就属于primary文件组,可省略(/*--数据文件的具体描述--*/ nametest, -- 主数据文件的逻辑名称 filenameD:\项目文件\淮矿\高科\test.mdf, -- 主数据文件的物理名称 size5mb, --主数据文件的初始大小 maxsize100mb, -- 主数据文件增长的…...
东莞网站建设网站制作公司/网络广告公司排名
//【1】filter()应用到数组上(修改上面的例子,去除为1的元素)let arr [1, 1, 2]arr arr.filter(item > {return item ! 1})console.log(arr) // [2]//【2】filter()应用到数组对象上(去除对象数组num为0的产品)let arr [{productId: 1,…...