当前位置: 首页 > news >正文

(转载)基于粒子群算法的多目标搜索算法(matlab实现)

1 理论基础

        在实际工程优化问题中,多数问题是多目标优化问题。相对于单目标优化问题,多目标优化问题的显著特点是优化各个目标使其同时达到综合的最优值。然而,由于多目标优化问题的各个目标之间往往是相互冲突的,在满足其中一个目标最优的同时,其他的目标往往可能会受其影响而变得很差。因此,一般适用于单目标问题的方法难以用于多目标问题的求解。
        多目标优化问题很早就引起了人们的重视,现已经发展出多种求解多目标优化问题的方法。多目标优化问题求解中最重要的概念是非劣解和非劣解集,两者的定义如下。
        非劣解(noninferior solution):在多目标优化问题的可行域中存在一个问题解,若不存在另一个可行解,使得一个解中的目标全部劣于该解,则该解称为多目标优化问题的非劣解。所有非劣解的集合叫做非劣解集(noninferior set)。在求解实际问题中,过多的非劣解是无法直接应用的,决策者只能选择其中最满意的一个非劣解作为最终解。最终解主要有三种方法,第一种是求非劣解的生成法,包括加权法、约束法、加权法和约束法结合的混合法以及多目标遗传算法,即先求出大量的非劣解,构成非劣解的一个子集,然后按照决策者的意图找出最终解。第二种为交互法,主要为求解线性约束多目标优化的Geoffrion法,不先求出很多的非劣解,而是通过分析者与决策者对话的方式,逐步求出最终解。第三种是事先要求决策者提供目标之间的相对重要程度,算法以此为依据,将多目标问题转化为单目标问题进行求解。
        利用进化算法求解多目标优化问题是近年来的研究热点,1967年,Rosenberg就建议采用基于进化的搜索来处理多目标优化问题,但没有具体实现。1975年,Holland提出了遗传算法,10年后,Schaffer提出了矢量评价遗传算法,第一次实现了遗传算法与多目标优化问题的结合。1989年,Goldberg在其著作《Genetic Algorithms for Search, Optimization, and Machine Learning》中,提出了把经济学中的Pareto理论与进化算法结合来求解多目标优化问题的新思路,对于后续进化多目标优化算法的研究具有重要的指导意义。目前,采用多目标进化算法求解多目标问题已成为进化计算领域中的一个热门方向,粒子群优化、蚁群算法、人工免疫系统、分布估计算法、协同进化算法、进化算法等一些新的进化算法陆续被用于求解多目标优化问题。本案例采用多目标粒子群算法求解多目标背包问题。

2 案例背景

2.1 问题描述

        假设存在五类物品,每类物品中又包含四种具体物品,现要求从这五种类别物品中分别选择一种物品放入背包中,使得背包内物品的总价值最大,总体积最小,并且背包的总质量不超过92 kg。背包问题的数学模型为

2.2 算法流程

        基于粒子群算法的二维多目标搜索算法流程如图10-1所示。其中,种群初始化模块随机初始化粒子的位置x和速度v,适应度值计算是指根据适应度值计算公式计算个体适应度值,粒子最优更新模块根据新的粒子位置更新个体最优粒子。非劣解集更新模块根据新粒子支配关系筛选非劣解。粒子速度和位置更新模块根据个体最优粒子位置和全局粒子位置更新粒子速度和位置。

2.3 适应度计算

        粒子适应度值参考式(10-1),每个个体的适应度值有两个,即价值和体积,同时个体须满足质量约束。

2.4 筛选非劣解集

        筛选非劣解集主要分为初始筛选非劣解集和更新非劣解集。初始筛选非劣解集是指在粒子初始化后,当一个粒子不受其他粒子支配(即不存在其他粒子的Px,Rx,均优于该粒子)时,把粒子放入非劣解集中,并且在粒子更新前从非劣解集中随机选择一个粒子作为群体最优粒子。更新非劣解集是指当新粒子不受其他粒子以及当前非劣解集中粒子的支配时,把新粒子放入非劣解集中,并且每次粒子更新前都从非劣解集中随机选择一个粒子作为群体最优粒子。

2.5 粒子速度和位置更新

        粒子更新公式如下:

2.6 粒子最优

        粒子最优包括个体最优粒子和群体最优粒子,其中个体最优粒子的更新方式是从当前新粒子和个体最优粒子中选择支配粒子,当两个粒子都不是支配粒子时,从中随机选择一个粒子作为个体最优粒子。群体最优粒子为从非劣解集中随机选择的一个粒子。

3 MATLAB程序实现

        根据多目标搜索算法原理,在MATLAB中实现基于粒子群算法的多目标搜索算法。
%% 该函数演示多目标perota优化问题
%清空环境
clc
clearload data%% 初始参数
objnum=size(P,1); %类中物品个数
weight=92;        %总重量限制%初始化程序
Dim=5;     %粒子维数
xSize=50;  %种群个数
MaxIt=200; %迭代次数
c1=0.8;    %算法参数
c2=0.8;    %算法参数 
wmax=1.2;  %惯性因子
wmin=0.1;  %惯性因子x=unidrnd(4,xSize,Dim);  %粒子初始化
v=zeros(xSize,Dim);      %速度初始化xbest=x;           %个体最佳值
gbest=x(1,:);      %粒子群最佳位置% 粒子适应度值 
px=zeros(1,xSize);   %粒子价值目标
rx=zeros(1,xSize);   %粒子体积目标
cx=zeros(1,xSize);   %重量约束% 最优值初始化
pxbest=zeros(1,xSize); %粒子最优价值目标
rxbest=zeros(1,xSize); %粒子最优体积目标
cxbest=zeros(1,xSize);  %记录重量,以求约束% 上一次的值
pxPrior=zeros(1,xSize);%粒子价值目标
rxPrior=zeros(1,xSize);%粒子体积目标
cxPrior=zeros(1,xSize);%记录重量,以求约束%计算初始目标向量
for i=1:xSizefor j=1:Dim %控制类别px(i) = px(i)+P(x(i,j),j);  %粒子价值rx(i) = rx(i)+R(x(i,j),j);  %粒子体积cx(i) = cx(i)+C(x(i,j),j);  %粒子重量end
end
% 粒子最优位置
pxbest=px;rxbest=rx;cxbest=cx;%% 初始筛选非劣解
flj=[];
fljx=[];
fljNum=0;
%两个实数相等精度
tol=1e-7;
for i=1:xSizeflag=0;  %支配标志for j=1:xSize  if j~=iif ((px(i)<px(j)) &&  (rx(i)>rx(j))) ||((abs(px(i)-px(j))<tol)...&&  (rx(i)>rx(j)))||((px(i)<px(j)) &&  (abs(rx(i)-rx(j))<tol)) || (cx(i)>weight) flag=1;break;endendend%判断有无被支配if flag==0fljNum=fljNum+1;% 记录非劣解flj(fljNum,1)=px(i);flj(fljNum,2)=rx(i);flj(fljNum,3)=cx(i);% 非劣解位置fljx(fljNum,:)=x(i,:); end
end%% 循环迭代
for iter=1:MaxIt% 权值更新w=wmax-(wmax-wmin)*iter/MaxIt;%从非劣解中选择粒子作为全局最优解s=size(fljx,1);       index=randi(s,1,1);  gbest=fljx(index,:);%% 群体更新for i=1:xSize%速度更新v(i,:)=w*v(i,:)+c1*rand(1,1)*(xbest(i,:)-x(i,:))+c2*rand(1,1)*(gbest-x(i,:));%位置更新x(i,:)=x(i,:)+v(i,:);x(i,:) = rem(x(i,:),objnum)/double(objnum);index1=find(x(i,:)<=0);if ~isempty(index1)x(i,index1)=rand(size(index1));endx(i,:)=ceil(4*x(i,:));        end%% 计算个体适应度pxPrior(:)=0;rxPrior(:)=0;cxPrior(:)=0;for i=1:xSizefor j=1:Dim %控制类别pxPrior(i) = pxPrior(i)+P(x(i,j),j);  %计算粒子i 价值rxPrior(i) = rxPrior(i)+R(x(i,j),j);  %计算粒子i 体积cxPrior(i) = cxPrior(i)+C(x(i,j),j);  %计算粒子i 重量endend%% 更新粒子历史最佳for i=1:xSize%现在的支配原有的,替代原有的if ((px(i)<pxPrior(i)) &&  (rx(i)>rxPrior(i))) ||((abs(px(i)-pxPrior(i))<tol)...&&  (rx(i)>rxPrior(i)))||((px(i)<pxPrior(i)) &&  (abs(rx(i)-rxPrior(i))<tol)) || (cx(i)>weight) xbest(i,:)=x(i,:);%没有记录目标值pxbest(i)=pxPrior(i);rxbest(i)=rxPrior(i);cxbest(i)=cxPrior(i);end%彼此不受支配,随机决定if ~( ((px(i)<pxPrior(i)) &&  (rx(i)>rxPrior(i))) ||((abs(px(i)-pxPrior(i))<tol)...&&  (rx(i)>rxPrior(i)))||((px(i)<pxPrior(i)) &&  (abs(rx(i)-rxPrior(i))<tol)) || (cx(i)>weight) )...&&  ~( ((pxPrior(i)<px(i)) &&  (rxPrior(i)>rx(i))) ||((abs(pxPrior(i)-px(i))<tol) &&  (rxPrior(i)>rx(i)))...||((pxPrior(i)<px(i)) &&  (abs(rxPrior(i)-rx(i))<tol)) || (cxPrior(i)>weight) )if rand(1,1)<0.5xbest(i,:)=x(i,:);pxbest(i)=pxPrior(i);rxbest(i)=rxPrior(i);cxbest(i)=cxPrior(i);endendend%% 更新非劣解集合px=pxPrior;rx=rxPrior;cx=cxPrior;%更新升级非劣解集合s=size(flj,1);%目前非劣解集合中元素个数%先将非劣解集合和xbest合并pppx=zeros(1,s+xSize);rrrx=zeros(1,s+xSize);cccx=zeros(1,s+xSize);pppx(1:xSize)=pxbest;pppx(xSize+1:end)=flj(:,1)';rrrx(1:xSize)=rxbest;rrrx(xSize+1:end)=flj(:,2)';cccx(1:xSize)=cxbest;cccx(xSize+1:end)=flj(:,3)';xxbest=zeros(s+xSize,Dim);xxbest(1:xSize,:)=xbest;xxbest(xSize+1:end,:)=fljx;%筛选非劣解flj=[];fljx=[];k=0;tol=1e-7;for i=1:xSize+sflag=0;%没有被支配%判断该点是否非劣for j=1:xSize+s if j~=iif ((pppx(i)<pppx(j)) &&  (rrrx(i)>rrrx(j))) ||((abs(pppx(i)-pppx(j))<tol) ...&&  (rrrx(i)>rrrx(j)))||((pppx(i)<pppx(j)) &&  (abs(rrrx(i)-rrrx(j))<tol)) ...|| (cccx(i)>weight) %有一次被支配flag=1;break;endendend%判断有无被支配if flag==0k=k+1;flj(k,1)=pppx(i);flj(k,2)=rrrx(i);flj(k,3)=cccx(i);%记录非劣解fljx(k,:)=xxbest(i,:);%非劣解位置endend%去掉重复粒子repflag=0;   %重复标志k=1;         %不同非劣解粒子数flj2=[];     %存储不同非劣解fljx2=[];    %存储不同非劣解粒子位置flj2(k,:)=flj(1,:);fljx2(k,:)=fljx(1,:);for j=2:size(flj,1)repflag=0;  %重复标志for i=1:size(flj2,1)result=(fljx(j,:)==fljx2(i,:));if length(find(result==1))==Dimrepflag=1;%有重复endend%粒子不同,存储if repflag==0 k=k+1;flj2(k,:)=flj(j,:);fljx2(k,:)=fljx(j,:);endend%非劣解更新flj=flj2;fljx=fljx2;end%绘制非劣解分布
plot(flj(:,1),flj(:,2),'o') 
xlabel('P')
ylabel('R')
title('最终非劣解在目标空间分布')
disp('非劣解flj中三列依次为P,R,C')

3.1 仿真结果

        本案例问题中,每类物品的价值、体积和质量如表10-1所列。
        从每类物品中选择一个物品放入背包,使背包的总价值最大,体积最小,并且背包总质量小于92kg。粒子群算法参数为:粒子个数为50,迭代次数为200,最终得到的非劣解在目标空间中的分布如图10-2所示。

 

由图10-2可知,算法搜索到的非劣解构成了Pareto面,算法搜索取得了很好的效果。

4 延伸阅读

        多目标搜索算法相对于单目标算法来说,更加贴近于实际问题,求解结果更具有参考价值。通过多目标搜索算法最终得到的不是一个最优解,而是一个非劣解集,需要从非劣解集中根据实际问题的需要选择一个解作为该问题的最终解。常用的基于进化算法的多目标搜索算法除了本案例介绍的方法之外,还有基于遗传算法的多目标搜索算法、基于免疫算法的多目标搜索算法等。

相关文章:

(转载)基于粒子群算法的多目标搜索算法(matlab实现)

1 理论基础 在实际工程优化问题中&#xff0c;多数问题是多目标优化问题。相对于单目标优化问题&#xff0c;多目标优化问题的显著特点是优化各个目标使其同时达到综合的最优值。然而&#xff0c;由于多目标优化问题的各个目标之间往往是相互冲突的&#xff0c;在满足其中一个…...

皮卡丘存储型xss、DOM型xss、DOM型xss-x

1.存储型xss 看题目&#xff0c;我们先留言&#xff0c;看它的过滤机制 发现可以永久存储并输出我们的留言 之后插入payload: <script>alert(xss)</script> 成功弹窗&#xff01; 2.DOM型xss Dom型xss&#xff0c;简单的说&#xff0c;就是向文档对象传入xss参…...

ThreadLocal源码

介绍 ThreadLocal是一个线程的本地变量&#xff0c;也就意味着这个变量是线程独有的&#xff0c;是不能与其他线程共享的。这样就可以避免资源竞争带来的多线程的问题。 但是&#xff0c;这种解决多线程安全问题的方式和加锁方式&#xff08;synchronized、Lock) 是有本质的区…...

Hive学习---3、DML(Data Manipulation Language)数据操作、查询

1、DML&#xff08;Data Manipulation Language&#xff09;数据操作 1.1 Load load语句可将文件导入到Hive表中 1、语法 load data [local] inpath filepath [overwrite] into table tablename [partition(partcol1val1,partcol2val2...)]2、关键字说明 &#xff08;1&…...

chatgpt赋能python:Python去除重复元素的几种方法

Python去除重复元素的几种方法 在Python编程中&#xff0c;去除列表、集合、字典等数据结构中的重复元素是一个常见的操作。本文将介绍Python中去除重复元素的几种方法&#xff0c;并分析它们的优缺点。 方法一&#xff1a;使用set去重 Set是Python中的一种集合类数据结构&a…...

2年测试我迷茫了,软件测试大佬都会哪些技能?我的测试进阶之路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…...

21天学会C++:Day7----auto关键字

CSDN的uu们&#xff0c;大家好。这里是C入门的第七讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. auto的使用 2.1 auto与指针和引用结合起来使用 2.2 在同一…...

Vue3 + ElementPlus实战学习——模拟简单的联系人列表管理后台

文章目录 &#x1f4cb;前言&#x1f3af;demo 介绍&#x1f3af;功能分析&#x1f9e9;数据的展示与分页功能&#x1f9e9;编辑功能&#x1f9e9;删除功能 &#x1f3af;部分代码分析&#x1f3af;完整代码&#x1f4dd;最后 &#x1f4cb;前言 这篇文章介绍一下基于 Vue3 和…...

【Go语言从入门到实战】并发篇

Go语言从入门到实战 — 并发篇 协程 Thread vs Groutine 相比之下&#xff0c;协程的栈大小就小很多了&#xff0c;创建起来也会更快&#xff0c;也更节省系统资源。 一个 goroutine 的栈&#xff0c;和操作系统线程一样&#xff0c;会保存其活跃或挂起的函数调用的本地变量…...

img标签请求 添加自定义header(二)

之前写过一篇关于img添加自定义请求头的处理方式&#xff08;点击这里&#xff09;&#xff0c;那么本篇我们来看另外几种实现方法。 自定义指令 以Vue为例&#xff0c;我们可以定义一个全局指令&#xff0c;对img标签进行一些处理。 <template><img :src"src…...

Set和weakSet Map和WeakMap

Set和weakSet的用法和区别 1.Set 和weakSet 它是类似于数组&#xff0c;且成员值都是唯一的&#xff0c; 2.Set有 add has delete clear size keys values forEach entries 3.weakSet 有add has delete 4.WeakSet中只能存放对象类型&#xff0c;不能存放基本类型 5.WeakSet它是…...

Qt基础之三十六:异常处理

本文将介绍如何在Qt中使用try...catch和调试dump文件来处理异常。 Qt版本5.12.6 一.使用try...catch 一段简单的捕获异常的代码,新建一个控制台工程,pro文件不用修改 #include <QCoreApplication> #include <QDebug>int main(int argc, char *argv[]) {QCoreA…...

【HMS Core】【ML Kit】活体检测FAQ合集

【问题描述1】 使用示例代码集成活体检测SDK时&#xff0c;报错state code -7001 【解决方案】 使用示例代码前请详细阅读示例工程中的“README”文件。您需要完成以下操作后才可以运行示例代码。 在AppGallery Connect网站下载自己应用的“agconnect-services.json”文件&a…...

ChatGPT:使用OpenAI创建自己的AI网站,使用 flask web框架快速搭建网站主体

使用OpenAI创建自己的AI网站 如果你还是一个OpenAI的小白&#xff0c;有OpenAI的账号&#xff0c;但想调用OpenAI的API搞一些有意思的事&#xff0c;那么这一系列的教程将仔细的为你讲解如何使用OpenAI的API制作属于自己的AI网站。 使用 flask web框架快速搭建网站主体 之前…...

后端(一):Tomcat

我们之前的前端是被我们一笔带过的&#xff0c;那不是我们要讲的重点&#xff0c;而这里的后端则是重点。本章先来认识认识后端的基础。 Tomcat 是什么 我们先来聊聊什么叫做tomcat&#xff0c;我们熟悉的那个是汤姆猫&#xff1a; 这和我们Java世界中的Tomcat 不是同一只猫&…...

华为OD机试之最小调整顺序次数、特异性双端队列(Java源码)

最小调整顺序次数、特异性双端队列 题目描述 有一个特异性的双端队列&#xff0c;该队列可以从头部或尾部添加数据&#xff0c;但是只能从头部移出数据。 小A依次执行2n个指令往队列中添加数据和移出数据。其中n个指令是添加数据&#xff08;可能从头部添加、也可能从尾部添加…...

2023年武汉住建厅七大员怎么报名?报名流程?精准题库一次过??

2023年武汉住建厅七大员怎么报名?报名流程&#xff1f;精准题库一次过&#xff1f;&#xff1f; 2023年武汉住建厅七大员是指施工员、质量员、资料员、材料员、机械员、标准员、劳务员&#xff0c;报的最多的可能就是施工员&#xff0c;质量员和资料员 报名流程&#xff1a; 1…...

Rust每日一练(Leetday0014) 组合总和II、缺失正数、接雨水

目录 40. 组合总和 II Combination Sum II &#x1f31f;&#x1f31f; 41. 缺失的第一个正数 First Missing Positive &#x1f31f;&#x1f31f;&#x1f31f; 42. 接雨水 Trapping Rain Water &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题…...

EnjoyVIID部署

1、下载 git clone https://gitee.com/tsingeye/EnjoyVIID.git 2、导入数据库 创建表enjoyviid 导入数据库(修改数据库文件里的编码) EnjoyVIID/sql/tsingeye-viid.sql 3、修改配置 vim EnjoyVIID/tsingeye-admin/src/main/resources/application-dev.yml 修改数据库连接、re…...

用Python解决爱因斯坦的数学问题

1 问题 有一条阶梯&#xff0c;若每步跨2阶&#xff0c;则剩最后一阶&#xff0c;若每步跨3阶&#xff0c;则最后剩2阶&#xff0c;若每步跨5阶&#xff0c;则最后剩4阶&#xff0c;若每步跨6阶&#xff0c;则最后剩5阶&#xff0c;只有每次跨7阶&#xff0c;最后才刚好不剩&am…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...