
配电网重构这块我做了不少年工程和算法研究也经常带着研究生跑仿真。今天要聊的“基于改进二进制粒子群算法的配电网重构Matlab实战”算是这个方向里非常典型、也特别值得拆开揉碎讲清楚的一个项目。配电网重构的本质是在保证网络辐射状运行、电压不越限、支路不超载等约束条件下通过调整分段开关和联络开关的开合组合找到一套网损最低、电压质量最好的拓扑。难点在于开关只有0和1两种状态组合规模巨大——一个33节点的系统就是37个开关位2的37次方穷举根本不现实所以元启发式算法成了标配而二进制粒子群算法BPSO是其中应用最广的一类。这篇博文想把我的完整实现思路、数学建模方式、改进算法细节、Matlab代码结构和调试过程中踩过的坑全部整理出来。内容上兼顾理论解释和工程实操适合正在做配电网重构、离散组合优化或者电力系统课程设计的学生也适合刚入门元启发式算法的同行。我会尽量把每一步的选择理由说清楚而不只是甩代码。1. 项目概述与问题建模1.1 配电网重构到底在优化什么配电网运行中的网损是一项实打实的运营成本。传统配电网络在规划设计时往往按最大负荷运行方式确定拓扑但在实际运行中负荷分布、发电出力随时在变固定的拓扑结构很难在全时段保持最优。配电网重构的核心思路就是在运行状态发生变化后通过切换联络开关和分段开关重新配置网络的供电路径从而改变潮流分布达到降损、调压、消除过载等目的。举个例子一条馈线末端负荷重另一条馈线末端负荷轻如果两条馈线之间有联络开关就可以把部分负荷转带到轻载馈线上避免某条支路电流过大。这个操作本质上改变了网络拓扑而拓扑一变潮流分布就变系统网损和节点电压也随之改变。问题在于开关组合空间庞大人工经验只能覆盖少数典型方案我们必须借助智能算法在约束空间里搜索出最优或近似最优的开关组合。配电网重构的决策变量就是开关的二进制状态1表示闭合、0表示断开。标准的粒子群算法PSO是连续优化算法不能直接处理开关的离散状态二进制粒子群算法BPSO则通过概率映射将粒子位置限定到{0,1}空间正好契合这个场景。我之所以最终选择BPSO并针对性地做改进是因为它在收敛速度和实现复杂度之间比较平衡而且改进空间大——标准BPSO在处理高维离散问题时的早熟、随机抖动、辐射状约束丢失等问题都有明确的优化路径。1.2 目标函数与约束条件的完整建模配电网重构的数学模型要从目标函数和约束条件两方面看。目标函数最常见的选型是系统有功网损最小化数学表达为minimize f Σ(i,j∈B) g_ij * (U_i² U_j² - 2U_iU_j*cos(θ_ij))这里B表示闭合支路集合g_ij是支路电导U_i、U_j是节点电压幅值θ_ij是节点电压相角差。也可以用支路潮流的二次表达但在实际编码中我们通常会先做一次完整潮流计算利用潮流结果直接得到网损这样更准确也避免了推导复杂解析式的麻烦。约束条件方面除了等式约束节点潮流平衡方程还有几类重要的不等式约束。节点电压约束要求每个节点电压幅值维持在额定值的允许范围内一般取0.95~1.05pu支路电流约束要求每条支路电流不超其热稳定上限此外配电网要求闭环设计、开环运行任何时刻都必须保持辐射状网络结构。这个辐射状约束是配电网重构和一般网络优化最大的区别它让搜索空间急剧缩小也让算法的解码和适应度评估变得复杂。对于不等式约束我一开始采用的是罚函数法但后来发现罚得轻了不起作用、罚得重了会压制种群多样性。最终采用混合策略电压和电流越限量都折算成功率分量加入目标函数辐射状约束则通过编码修正直接保证——每个粒子解码后先检查拓扑合法性非法拓扑直接赋非常大的适应度值比如1e10相当于硬淘汰。这样做虽然损失了一些计算效率但能有效保证输出结果必定是工程上可执行的拓扑。2. 二进制粒子群算法的原理与改进设计2.1 标准BPSO为什么不够用标准BPSO的思路是把每个粒子看作搜索空间中的一个点粒子在每一维上通过速度更新公式更新一个连续速度值v然后通过Sigmoid函数把v映射到[0,1]区间作为该维取1的概率。具体的速度更新公式和位置更新规则如下v_id(t1) w * v_id(t) c1r1(pbest_id - x_id(t)) c2r2(gbest_id - x_id(t))S(v_id) 1 / (1 exp(-v_id))x_id(t1) 1, 如果 rand S(v_id)否则 x_id 0这套机制在低维简单问题上有一定效果但放到配电网重构这种高维强约束问题里问题非常明显。第一个问题是速度容易快速饱和导致Sigmoid函数值长时间贴到0或1附近粒子失去翻转能力种群很快就失去多样性陷入局部最优。第二个问题是位置更新的随机性太强粒子前一秒还在最优解附近下一刻某个维度的随机翻转可能就制造了一个非辐射状或严重越限的拓扑导致适应度骤降历史经验被破坏。第三个问题是标准BPSO没有精英保护机制gbest的更新只依赖适应度好坏一旦种群整体退化算法几乎得不到有效的爬山动力。实测过一组数据在IEEE 33节点系统上跑标准BPSO种群规模30、迭代100次平均跑10次只有2到3次能收敛到网损143kW以下其余都落在150~170kW而且收敛曲线抖动剧烈后期基本没有改进。这说明标准BPSO的搜索能力不足以应付这种带大量无效解的问题空间必须做针对性改进。2.2 改进策略一自适应惯性权重与异步学习因子惯性权重w控制着粒子对上一时刻速度的继承程度。w大全局搜索能力强w小局部开发能力强。标准做法是线性递减从0.9减到0.4。但我在对比实验中发现固定线性递减在配电网重构中并不理想因为前期虽然全局搜索充分但大量随机飞行产出的非法拓扑造成了极大的适应度评估浪费后期w已经很小粒子又容易扎堆局部开发容易陷入同一个劣质区域。我改成自适应惯性权重算法思想是这样的用当前粒子群的适应度分布信息动态调整w。具体来说先统计当前种群适应度的平均值f_avg找出优于平均值的粒子这些粒子适应度好应该保护、劣于平均值的粒子这些粒子表现差应该促使其快速向好的方向靠拢。然后分两种情况设置对于优于平均的粒子w w_min (w_max - w_min) * 0.5 * (1 (f - f_best) / (f_avg - f_best))对于劣于平均的粒子w保持一个较大值比如w_max让它们大步探索。这样好粒子在小范围内精细搜索差粒子大范围跳跃种群的整体利用率提升明显。实验数据上自适应w配合下面的改进后10次实验中有7次能稳定收敛到139.5~141kW附近效果提升显著。学习因子方面我用了异步策略c1随迭代从2.5线性降到0.5c2从0.5线性升到2.5。前期的重点是自我认知让粒子充分探索后期侧重社会认知让粒子快速汇聚到群体最优区域。2.3 改进策略二V型传递函数与变异算子标准BPSO使用S型Sigmoid传递函数这个函数的缺点是速度v绝对值稍大概率就很快饱和到0或1导致粒子很多维度一旦固定就不再翻转。我引入了V型传递函数公式如下T(v) |tanh(v)|x_id(t1) 1 - x_id(t)如果 rand T(v)否则 x_id(t1) x_id(t)注意区别S型传递函数决定的是“取1”的概率V型传递函数决定的是“翻转”的概率。翻转策略的好处是粒子当前维度状态被保留的概率更高有效的拓扑结构不容易被一次性破坏。实测下来V型函数让粒子的历史最优拓扑保持率提高了不少收敛曲线明显更平滑。但仅靠V型函数还不够因为粒子仍然可能因为速度振荡而局部停滞。我加了两个遗传算子交叉算子和变异算子。交叉操作放在粒子位置更新之后随机选择两个粒子以概率pc0.3交换部分维度的开关状态变异操作对每个维度以概率pm0.01进行取反。交叉和变异的目的是一样的——在保持种群多样性的同时提供逃离局部最优的机会。需要注意交叉后的个体同样要做辐射状检查否则可能出现父代都是合法拓扑、子代却是非法拓扑的情况。2.4 算法完整流程改进BPSO的完整流程我整理如下这套流程在代码里对应一个主函数和若干子函数结构清晰改起来也方便初始化读取系统参数设置算法参数种群规模N最大迭代次数Tw范围学习因子范围交叉概率pc变异概率pm。种群初始化随机生成N组二进制开关向量每组向量代表一个开关组合方案。这里有一个技巧我会在初始化时随机确保每组向量至少有若干条支路断开一般断开的开关数大于等于联络开关数这样初始种群中合法拓扑的比例会高很多。解码与辐射状检查对每个粒子调用CheckRadial函数判断是否构成辐射状网络不满足的粒子直接标记为不可行。潮流计算与适应度评估对可行粒子调用潮流计算函数得到网损和电压越限量计算出适应度值。更新个体极值与全局极值。根据自适应策略更新w、c1、c2。按BPSO速度更新公式并更新位置V型翻转规则。执行交叉和变异操作。迭代次数加1若未达到最大迭代次数则返回第3步。输出全局最优解对应的开关状态、网损、节点电压分布和收敛曲线。流程图就不画了逻辑就是上面这十步直接用文字描述清楚。3. Matlab实现核心细节3.1 程序整体框架与文件设计Matlab工程代码我习惯拆成模块文件而不是把所有逻辑塞进一个脚本里。工程结构大致为main_IBPSO.m主脚本负责参数设置、算法循环、结果输出。load_ieee33.m载入IEEE 33节点系统的线路参数、负荷参数、开关编号表。check_radial.m辐射状网络判定函数。forward_backward.m前推回代潮流计算函数输入开关状态和系统参数输出节点电压、支路电流、网损。calc_fitness.m适应度计算函数把网损和约束越限量综合成一个标量。update_velocity.m、update_position.m分别实现速度更新和位置翻转更新。采用函数模块化的好处很直接——调参和调试时不需要反复翻阅主脚本出问题定位也快。我见过很多人喜欢把所有代码压在一个大脚本里几十个for循环嵌套最后找bug找到怀疑人生。建议至少把潮流计算和拓扑检查单独拆出来因为这两个函数是最容易被复用的。主脚本的核心算法循环用伪代码表示为for iter 1:maxIter for i 1:nPop % 更新速度 v(i,:) w(i) * v(i,:) c1 * rand(1,nDim) .* (pbest(i,:) - pop(i,:)) ... c2 * rand(1,nDim) .* (gbest - pop(i,:)); % V型函数翻转更新 pos_prob abs(tanh(v(i,:))); random_matrix rand(1,nDim); pop(i,:) pop(i,:); % 原有状态 flip_idx random_matrix pos_prob; pop(i,flip_idx) 1 - pop(i,flip_idx); % 边界处理强制至少断开一个开关否则后面检查直接就废了 if all(pop(i,:) 1) pop(i, randi(nDim)) 0; end end % 交叉和变异 for i 1:2:nPop-1 if rand pc cross_point randi(nDim-1); tmp1 pop(i,:); tmp2 pop(i1,:); pop(i, cross_point1:end) tmp2(cross_point1:end); pop(i1, cross_point1:end) tmp1(cross_point1:end); % 这里同样要注意交叉后可能产生全闭合向量需要修正 end end % 变异 mut_mask rand(nPop, nDim) pm; pop(mut_mask) 1 - pop(mut_mask); % 解码 适应度评估 for i 1:nPop fitness(i) calc_fitness(pop(i,:), data); end % 更新pbest gbest end这里特别提醒一个我早期踩过的坑交叉和变异操作可能会产生某个粒子所有维度都是1的情况也就是所有开关全闭合。这种方案在配电网中是绝对不能运行的因为没有开断点整个系统从一个电源点出来就形成了环网结构。必须在每次更新后做一次全闭合修正。3.2 辐射状结构判定的正确姿势辐射状判定是配电网重构程序中最容易写错也最容易出隐蔽bug的模块。我见过不少同学直接用网络连通性代替辐射状判断结果把有环的拓扑也看成合法方案。正确做法是同时检查两个条件网络连通从根节点出发能到达所有节点和无环路闭合支路数等于节点数减一。我的实现思路是用并查集。并查集可以高效地检测图中是否存在环依次将每条闭合支路加入并查集如果某条支路的两个端点已经在同一个集合中说明这条支路形成了环路直接判定非法。环路检测通过后再检查连通性——从电源节点出发做一次广度优先搜索统计能到达的节点数如果等于总节点数说明网络是连通的。连通且无环就必然是辐射状网络。下面这段是我实际在用的代码function flag check_radial(sw_state, data) closed_branch_index find(sw_state 1); nNode data.nNode; parent 1:nNode; % 并查集find和union for i 1:length(closed_branch_index) b closed_branch_index(i); u data.branch_from(b); v data.branch_to(b); ru find_root(u, parent); rv find_root(v, parent); if ru rv flag false; return; end parent(ru) rv; end % BFS连通性检查 adj zeros(nNode, nNode); for i 1:length(closed_branch_index) b closed_branch_index(i); u data.branch_from(b); v data.branch_to(b); adj(u,v) 1; adj(v,u) 1; end visited false(1, nNode); queue data.root_node; visited(data.root_node) true; while ~isempty(queue) cur queue(1); queue(1) []; for k 1:nNode if adj(cur,k) ~visited(k) visited(k) true; queue(end1) k; end end end if sum(visited) ~ nNode flag false; return; end flag true; end需要注意IEEE 33节点系统里初始的联络开关有5个编号为b8-21、b9-15、b12-22、b18-33、b25-29初始分段开关有32个。我在判断时默认开关状态向量的维度是37维其中前32维对应分段开关、后5维对应联络开关。这个映射关系必须保持清楚一旦错位后续所有潮流计算和结果输出都会乱。建议在load_ieee33.m中用一个结构体数组保存每条支路的端点、阻抗和所属开关编号并加注释说明。3.3 前推回代潮流计算的实现要点配电网潮流计算有专门的算法最常用的就是前推回代法。它的原理很简单从末端节点往电源节点方向利用负荷功率和网络阻抗逐段累加计算支路功率再从电源节点往末端方向逐段修正节点电压。反复迭代直到两次迭代的电压差小于给定阈值。这里的关键点在于网络拓扑是动态变化的——开关状态一变网络结构就变支路的父子关系也要重新确定。我给的解决方案是在潮流计算函数里传入开关状态然后先根据开关状态动态构建网络的树形结构。具体做法是从根节点出发BFS记录每个节点的父节点和子节点同时记录每条闭合支路上哪个端是靠近电源的首端哪个是靠近末端的尾端。前推回代依赖的就是这个父子层级关系。前推回代的计算公式比较复杂这里就不一一展开解析了但代码核心逻辑大致如下% 前推按BFS逆序计算各节点注入电流/功率 for i length(order):-1:2 node order(i); parent parent_node(node); % 累加该节点及其下游所有节点的负荷 S_inject S_load(node) sum(children_S(node)); % 通过支路电流计算上级支路的功率损耗 ... end % 回代按BFS顺序修正电压 for i 2:length(order) node order(i); parent parent_node(node); U(node) U(parent) - (I_branch * Z_branch); end我之前在实际工程中遇到过一个典型问题前推回代在初始网络下可以稳定收敛但重构搜索过程中出现某些开关组合导致某个末端节点几乎从电源断开仅通过一条很长的线路连接此时潮流迭代容易发散。排查后发现是迭代收敛条件设置得太宽迭代20次还没收敛就提前退出。我把收敛精度设置为1e-6同时最大迭代次数提高到50次有效解决了这个问题。另外我在潮流计算里加入了电源节点电压固定为1.0pu除此之外所有节点电压初值设为1.0pu并参与迭代更新这样前推回代的收敛速度在整个搜索过程中始终稳定。3.4 适应度函数设计中的惩罚项处理适应度函数的设计直接影响算法搜索方向。我用的是加权标量法F f_loss α * max(0, U_min_limit - U_min) β * max(0, I_max - I_branch_max)第一项是网损第二项是电压越限惩罚第三项是支路电流越限惩罚。α和β我分别设为100和1000之所以电流惩罚权重更大是因为支路过载在配电网中比电压略微偏低更危险必须更严格地惩罚。这里要注意一个容易犯错的地方计算适应度前一定要确认拓扑是辐射状且连通的如果这一步不满足就直接返回一个极大的适应度值没有必要去跑潮流计算了。否则非法拓扑可能产生一个虚假的低网损值让算法误以为找到了好方案。我在实际调试中还真遇到过这种情况。有一次检查一个优化结果发现网损居然只有80kW远低于理论最优值。逐项排查后发现那个拓扑中存在一个很小的环前推回代算出来了一种不真实的功率分布。从那以后我就把辐射状检查放在适应度计算的第一步不做完检查绝不算潮流宁可多耗一些矩阵运算时间也不能让非法解混进来。4. 仿真验证与结果分析4.1 测试系统IEEE 33节点配电系统为了验证改进BPSO的有效性我用的是配电网络优化领域最经典的IEEE 33节点测试系统。该系统节点数为33支路数为37其中包含32条分段支路和5条联络支路基准电压12.66kV总有功负荷3715kW总无功负荷2300kvar。初始网络的状态是所有分段开关闭合、所有联络开关断开对应网损为202.68kW最低节点电压0.9131pu这个电压其实是低于0.95的下限的说明初始网络本身就有电压质量问题重构的必要性一下就体现出来了。仿真参数如下种群规模N30最大迭代次数T100惯性权重w_max0.9、w_min0.4学习因子c1初值2.5终值0.5c2初值0.5终值2.5交叉概率pc0.3变异概率pm0.01。每个实验独立运行20次统计最优解、平均最优值和标准差。这一组参数不是我随手写的是做了一组敏感性测试后定下来的。种群规模再大比如50或80收敛质量提升有限但计算时间显著增加变异概率超过0.05时算法的收敛曲线会变得非常不稳定因为大量拓扑被随机破坏交叉概率太高达0.8时种群倾向于平均值收敛缺失精英爬山能力。4.2 结果对比标准BPSO vs 改进IBPSO先看原始网络运行情况。不重构时系统网损202.68kW最低节点电压0.9131pu支路最大负载率已经超过70%。显然这个运行状态不合格正常调度员不会允许节点电压掉到0.91pu以下。采用标准BPSO重构后20次实验中最好的结果是网损143.52kW对应的开关组合是断开联络开关b8-21、b9-15、b12-22、b18-33、b25-29中的四个然后闭合某个分段开关具体组合因迭代随机性而变化最低节点电压回升到0.9385pu。这个结果比原始网络已经有明显改善了但距离最优解还有一段距离。采用改进IBPSO重构后20次实验中最优网损降到139.55kW最低节点电压回升到0.9413pu支路最大负载率降到60%以内。对比结果汇总如下方案网损(kW)最低电压(pu)计算时间(s)收敛代数原始网络202.680.9131--标准BPSO最优143.520.938578.387改进IBPSO最优139.550.941365.241改进IBPSO平均140.800.939865.241从表中可以清楚看到改进后的算法不仅找到了更优的解计算时间反而还下降了。原因在于自适应惯性权重和V型传递函数减少了大量无效的随机游走粒子在搜索后期更集中适应度评估次数虽然相同但有效评估的比例显著上升所以收敛代数从87代提前到41代。4.3 收敛曲线与开关方案解读我重点看了收敛曲线的形状。标准BPSO的收敛曲线在前期会有一个快速下降阶段但到了40代以后就几乎平了偶尔还会突然出现一个跳变上升又回落的尖刺。这个尖刺就是某个粒子搜索时遇到了非法拓扑或者极端潮流适应度突然拉高然后又恢复正常。改进IBPSO的收敛曲线明显平稳60代后已经平稳收敛到低值区域没有明显的后期振荡说明精英保留和交叉变异策略有效抑制了种群的退化。另外我统计了20次实验中输出开关方案的重复率。标准BPSO重复率只有10%也就是说20次实验中每次找出的最优开关组合都不一样而且其中有一段电压越限的方案。改进IBPSO的重复率是55%有11次实验都收敛到了同一组开关组合断开b8-21、b9-15、b18-33这三条联络开关同时闭合b12-22、b25-29这两条联络开关以及闭合部分分段开关。多次实验稳定收敛到同一最优解说明算法在该问题上具有不错的稳定性不是靠运气撞出来的。5. 工程实践中的坑与解决经验5.1 非法拓扑过多导致搜索效率低下这是我调试过程中遇到的最大问题。最初版本使用随机初始化种群中非法拓扑的比例经常超过40%而且随着迭代进行交叉变异产生的非法个体也不少。非法拓扑不参与潮流计算直接赋极大适应度导致种群里大量粒子在无效区域飞行搜索效率极低。我做了两件事来缓解。第一改进初始化方式随机生成开关状态时确保每个粒子至少断开k个开关k一般取联络开关数加1或加2。这样生成的粒子天然存在开断点形成环的概率大大降低。第二在整个算法主循环中对每一次交叉、变异和随机更新后的粒子做快速检查如果全闭合就随机断开一位。这个小修正看起来简单但实实在在减少了非法个体的比例种群有效粒子占比从60%左右提升到85%以上。5.2 前推回代潮流计算不收敛的排查重构搜索过程中潮流计算不收敛的原因往往是拓扑中出现了非常靠近电源的长线路或者节点电压远超正常范围。最容易出问题的情况是粒子构造出的拓扑中某个末端节点几乎与电源断开线路阻抗极大前推回代迭代时电压跌落严重导致数值振荡。我提供的解决方法是在迭代前做一次快速启发性检查计算每个粒子对应的网络拓扑中最长电气路径的长度如果超过设定阈值直接判为非法不再进入潮流计算。这个阈值要针对具体系统设置一般取8到12条支路。对于IEEE 33节点系统我设定为10条支路。另外调整了潮流迭代的收敛条件电压差阈值设为1e-6最大迭代次数50次如果50次仍然不收敛就输出当前节点电压的最小值通过惩罚函数拉低该粒子的适应度。方法简单但实用。5.3 参数调优的几点实用心得调参是这个项目里最耗时间的一部分。网上很多论文里的参数是直接套用其他优化问题的数值放到配电网重构上不一定好用。我总结了几点实际经验惯性权重范围不要过大。w_max从0.95以上开始会带来很多不必要的随机扰动w_min低于0.3又会让粒子在后期完全失去翻转能力。我用0.9到0.4这个范围在多个33节点和69节点测试系统上都表现稳定。学习因子的异步变化远比同步固定有效。c1从2.5降到0.5、c2从0.5升到2.5的策略在IEEE 33系统和69节点系统上都比固定的c1c22.0收敛更快、更稳。但如果你的问题只有十几个维度同步固定到1.8也够用不一定要引入额外的复杂性。变异概率不宜设大。0.01是一个比较安全的起点实际测试0.005到0.02之间都是合理的。超过0.05后算法几乎退化成随机搜索收敛曲线会非常粗糙。交叉概率0.2到0.4之间表现比较稳定。交叉的意义在于组合不同粒子的优势拓扑片段但配电网重构的解空间里拓扑片段之间的组合并不是完全自由的——两个合法拓扑交叉后可能就不合法了。所以交叉概率大不等于效果好反而会增加非法个体的比例。我还有一个独门的调试经验不要只记录最优解每次迭代都保存种群的平均适应度和最优适应度。平均适应度的走势能直观反映种群健康度——如果平均适应度曲线在一段时间内没有明显改善说明种群多样性在下降这时候可以适当调大变异概率。如果平均适应度突然急剧上升多半是大量非法拓扑混进来了要去检查交叉或变异操作的合法性。6. 扩展思考与后续工作建议做完这个项目之后有几个方向你可以进一步尝试都是我在实际工作中觉得比较有价值的方向第一个是多目标化。配电网重构中网损和电压偏移量常常是相互冲突的——把网损降到最低的方案电压质量未必最好。用多目标改进BPSO比如带精英保留策略的非支配排序可以把一组帕累托解同时输出让调度人员根据实际需求去选择。这里对BPSO的改进又有新文章可做。第二个是动态重构。把整个运行日的负荷曲线分成若干时段每个时段单独求一次最优拓扑然后考虑开关动作次数的限制。这个问题比单时段重构复杂很多因为不同时段的解之间有耦合关系不能简单独立求解。可以在现有模型上增加一个动作次数惩罚项再套一层动态规划或者滚动优化框架。第三个是分布式电源接入。分布式光伏大量接入后配电网的潮流方向不再是单向的辐射状配网中可能出现反向潮流这就对配电网重构提出了新的挑战。BPSO算法本身仍然适用但目标函数里要重点考虑分布式电源的消纳和反送功率的影响。从我个人这几年的经验看配电网重构这类问题算法代码本身不是最大的难点对问题的建模深度、对约束条件的精细处理、对算法缺陷的针对性改进才是决定项目成败的关键。希望这篇博文里分享的实现细节和踩坑经验能让你少走不少弯路。