ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

二维矩形排样优化:从数学建模到MATLAB算法实现

二维矩形排样优化:从数学建模到MATLAB算法实现 1. 从“一刀切”到“精打细算”工业零件切割优化的现实困境如果你在工厂里待过或者接触过金属加工、木材加工、玻璃切割这类行业一定会对一个场景非常熟悉一块巨大的原材料板材比如钢板、木板或者亚克力板被送到切割机前。工程师或者老师傅拿着图纸上面密密麻麻画着几十上百个不同形状、不同尺寸的零件。他们的任务就是想办法把这些零件“塞”进这块板材里尽可能多地切出来同时让剩下的边角料越少越好。这听起来像不像一个高级版的“俄罗斯方块”游戏只不过这个游戏的规则更复杂零件形状可能不规则不是简单的矩形板材可能有瑕疵区域不能用切割机有切割路径和起刀点的限制不同零件的需求量也不同不是越多越好。更重要的是这直接关系到真金白银。原材料成本在制造业中占比巨大切割利用率每提高一个百分点对于大规模生产来说可能就是几十万甚至上百万的成本节约。2020年华数杯数学建模竞赛的B题正是抓住了这个在工业生产中极具普遍性和经济价值的核心问题——工业零件切割优化。它不是一个纯理论的数学游戏而是直接来源于车间里的实际痛点。题目通常会提供一系列不同尺寸的矩形零件这是简化模型但原理相通和固定尺寸的原材料板材要求参赛者设计一种或多种排样方案在满足所有零件需求的前提下使得使用的板材张数最少或者总体利用率最高。很多初次接触这类问题的人可能会想当然地认为“这有什么难的就像拼图一样把零件紧挨着放尽量填满不就行了” 或者用一些简单的规则比如“先放大零件再放小零件”。但实际操作和理论优化之间隔着一条巨大的鸿沟。手工排样极度依赖经验且难以达到全局最优而简单的贪心算法每次都选当前看起来最好的放置方式很容易陷入局部最优解造成板材的浪费。这就是我们需要数学建模和优化算法介入的原因用精确的计算和搜索策略替代人眼的估算和经验找到那个真正“精打细算”的最优或近似最优方案。这道题目的价值在于它将一个具体的工程问题抽象成了一个经典的组合优化问题即“二维矩形排样问题”或“二维切割下料问题”。解决它不仅需要理解优化理论更需要将理论转化为可执行的计算机算法并用MATLAB或LINGO这样的工具实现出来。接下来我们就深入这个问题的内部看看如何一步步拆解并攻克它。2. 问题本质与数学模型构建把现实问题“翻译”成数学语言面对一个优化问题第一步也是最关键的一步就是完成从“物理世界”到“数学世界”的准确映射。对于矩形零件切割我们需要定义清楚所有的要素和规则。2.1 核心要素定义假设我们有原材料板材 宽度为W 高度为H通常假设板材足够长或数量无限我们优化的是单张板材上的布局然后重复使用。为简化我们先考虑单张板材的优化目标是利用率最高。多张板材的优化可以转化为多次调用单张板材优化并考虑零件需求总量的约束。待切割零件 共有n种矩形零件。第i种零件的尺寸为宽度w_i 高度h_i 需求数量为d_i。 这里有一个非常重要的细节零件是否可以旋转在大多数实际场景中矩形零件是可以90度旋转的这意味着放置时可以选择(w_i, h_i)或(h_i, w_i)两种朝向。这虽然增加了灵活性但也让问题的复杂度翻倍。切割工艺约束 这是数学模型与实际情况接轨的核心。常见的约束有正交切割 所有切割线都必须平行于板材的边。这是最基本的前提。一刀切Guillotine Cutting 切割必须从板材的一边开始一刀切到对边将板材分成两块。然后每一块可以继续用同样的方式切割直到得到所需零件。这种切割方式对某些切割设备如龙门式切割机是必需的因为它简化了切割路径。非一刀切Non-guillotine Cutting则允许更复杂的切割顺序利用率可能更高但设备和控制更复杂。零件间间距 考虑到切割刀的宽度刀缝损耗或热变形激光、等离子切割零件之间可能需要预留一定的间隙g。板材边界留白 板材边缘可能需要预留一定距离用于夹持或避免边缘缺陷。对于数学建模竞赛通常会在题目中明确这些约束。我们以最经典、最普遍的“正交、允许旋转、无一刀切限制、考虑间距”的二维排样问题为例来构建模型。2.2 决策变量设计如何用数学变量来描述一个零件被放在板材的什么位置最直观的方法是定义每个零件的左下角坐标。设零件i的第j个实例因为需求可能大于1的放置位置为(x_ij, y_ij) 其旋转状态为r_ijr_ij 0表示不旋转r_ij 1表示旋转90度。那么这个实例所占用的矩形区域就是如果不旋转从(x_ij, y_ij)到(x_ij w_i, y_ij h_i)如果旋转从(x_ij, y_ij)到(x_ij h_i, y_ij w_i)但是这样定义变量会非常庞大实例数多且不利于处理“零件是否重叠”的约束。在优化建模中更常用的是一种基于“相对位置”的建模思想。2.3 建立数学模型混合整数线性规划MILP我们可以为每对零件包括将板材本身视为一个特殊的“零件”定义它们之间的相对位置关系。对于任意两个矩形块i和j代表零件实例或板材边界要保证它们不重叠至少满足以下四个条件之一i在j的左边x_i w_i x_ji在j的右边x_i x_j w_ji在j的下边y_i h_i y_ji在j的上边y_i y_j h_j这四种情况是互斥的必须且只能选择一种成立。为了用数学公式表达这种“或”的关系我们需要引入二元决策变量0-1变量。定义四组0-1变量a_ij, b_ij, c_ij, d_ij。 例如a_ij 1表示条件1i在j左成立。那么不重叠约束可以写为x_i w_i x_j M * (1 - a_ij)x_i x_j w_j - M * (1 - b_ij)y_i h_i y_j M * (1 - c_ij)y_i y_j h_j - M * (1 - d_ij)a_ij b_ij c_ij d_ij 1其中M是一个足够大的正数通常取板材长宽之和这是一个经典的“大M法”建模技巧。当a_ij1时第一个约束是紧的必须满足i在j左其他约束因为M的存在而松弛自动满足。最后一个约束保证了至少有一个相对位置条件成立。目标函数 对于单张板材优化我们可以设定目标为最大化板材利用率即所有已放置零件的总面积之和。也可以设定为在满足所有零件需求的前提下最小化使用的板材张数这通常需要引入更高层次的决策哪些零件放在哪张板上。边界约束 所有零件的放置必须在板材范围内0 x_i W - w_i(或旋转后的宽度)0 y_i H - h_i(或旋转后的高度)需求约束 每种零件i放置的总实例数等于其需求量d_i。至此我们得到了一个完整的混合整数线性规划MILP模型。它的优点是精确、严谨能在理论上找到全局最优解。但缺点也极其明显当零件数量稍多比如超过20个0-1变量和约束的数量会爆炸式增长导致问题规模太大即使是最先进的商业求解器如Gurobi, CPLEX也可能在可接受时间内无法求解。这正是此类问题的挑战所在也是启发式算法大显身手的地方。3. 算法策略选择精确求解与启发式搜索的权衡既然精确的MILP模型难以直接求解大规模问题我们就需要更高效的算法策略。在实际的数学建模竞赛和工程应用中通常会采用分层或混合的策略。3.1 精确求解器尝试LINGO/Gurobi对于小规模问题例如零件种类少于10总需求数少于15我们完全可以尝试使用LINGO直接求解上述MILP模型。LINGO的语法相对直观适合描述优化模型。! 示例LINGO模型骨架 (概念性非完整代码) MODEL: SETS: ITEM: w, h, d; ! 零件集合属性宽高需求 INSTANCE(I, J): x, y, r; ! 实例集合属性x坐标y坐标旋转(0/1) ENDSETS DATA: ! 在这里输入W, H, 以及每个零件的w, h, d ENDDATA ! 目标最大化利用率总零件面积 MAX SUM(INSTANCE(I, J): (1-r)*w(I)*h(I) r*h(I)*w(I)); ! 边界约束 FOR(INSTANCE(I, J): x(I, J) 0; y(I, J) 0; x(I, J) (1-r(I,J))*w(I) r(I,J)*h(I) W; y(I, J) (1-r(I,J))*h(I) r(I,J)*w(I) H; ); ! 需求约束 FOR(ITEM(I): SUM(INSTANCE(I, J): 1) d(I); ); ! 不重叠约束需用大M法实现此处略去复杂表达 ! ... END注意 在LINGO中完整实现“大M法”不重叠约束非常繁琐代码冗长且容易出错。更常见的做法是用LINGO解决小规模问题或问题的一部分或者验证启发式算法得到的结果。3.2 启发式算法主力MATLAB实现对于竞赛规模的问题启发式算法是绝对的主力。它们的核心思想是用智能的规则来构造解虽然不能保证全局最优但能在很短时间内得到非常优秀的可行解利用率通常在85%-95%以上。最经典、最有效的策略是基于左下角放置原则的贪心算法及其变种。3.2.1 核心思想左下角放置Bottom-Left, BL规则很简单总是将当前要放置的零件移动到尽可能靠下、靠左的位置。具体步骤初始化一个空的板材以及一个按某种规则排序的待放置零件列表。从列表中取出下一个零件。尝试将该零件考虑两种旋转方向放置到当前板材中所有可能的位置。所谓“可能的位置”是指放下后不与已放零件重叠且在板材边界内。在所有可能位置中选择使得零件放置后其左下角坐标的y值最小的位置如果y值相同则选择x值最小的位置。这就是“最左下角”。放置该零件更新板材的“占用状态”。重复2-5直到所有零件放置完毕或无法再放置。这个算法的效果高度依赖于第2步中零件的放置顺序。不同的顺序会产生截然不同的排样结果。因此如何生成这个顺序就成了算法优化的关键。3.2.2 放置顺序的生成策略简单规则 按面积从大到小排序、按周长从大到小排序、按最长边从大到小排序。通常先放大的、形状不规则的零件更容易获得高利用率。随机化与迭代改进 这是提升算法性能的核心。我们不只尝试一种顺序而是生成大量不同的随机顺序或基于某种规则的扰动顺序对每一种顺序都运行一遍BL算法最后选择利用率最高的那个排样方案。这种方法称为随机贪心或多起点搜索。遗传算法/模拟退火 将零件的排列顺序编码为“染色体”或“状态”以排样利用率作为适应度函数或能量函数。通过选择、交叉、变异遗传算法或概率性状态转移模拟退火来不断进化出更好的顺序。这类元启发式算法能更系统地在更大的解空间中搜索通常能得到比简单随机化更好的结果。3.2.3 关键子算法如何快速找到“可放置位置”这是BL算法实现中的性能瓶颈和难点。朴素的方法是遍历板材上每一个离散的像素点判断放置是否可行效率极低。高效的方法是维护一个“轮廓线Skyline”。轮廓线表示法 不记录每个像素的占用情况而是记录当前板材上沿x轴方向的一系列水平线段轮廓段的最高y坐标。这些轮廓段连接起来就像城市的天际线。放置判断 当要放置一个新矩形时我们沿着轮廓线从左到右扫描寻找一段足够宽大于等于矩形宽度的轮廓段。然后将矩形的底边对齐这段轮廓段的顶端计算放置后的新轮廓线。合并优化 放置矩形后更新轮廓线。可能会合并相邻的、高度相同的轮廓段以保持轮廓线的简洁。使用轮廓线法可以将位置判断的复杂度从O(板材面积)降低到O(轮廓线段数)极大提升了算法速度使得处理上百个零件的排样成为可能。4. MATLAB算法实现详解与代码剖析下面我将结合一个具体的、考虑零件旋转和间距的BL算法实现框架来详细讲解关键步骤和代码逻辑。我们假设板材尺寸为W和H 零件数据存储在parts矩阵中每行代表一种零件[w, h, d]gap为切割间隙。4.1 数据结构设计% 1. 输入数据 W 2440; H 1220; % 常见板材尺寸单位mm gap 2; % 切割间隙2mm parts [200 150 10; 180 100 15; 150 80 20; ...]; % [宽度高度需求数量] % 2. 零件列表展开 % 将每种零件的需求数量展开得到一个长长的待排列表 part_list part_list []; for i 1:size(parts, 1) w parts(i, 1); h parts(i, 2); d parts(i, 3); part_list [part_list; repmat([w, h], d, 1)]; % 每个实例记录其原始尺寸 end num_parts size(part_list, 1); % 3. 定义轮廓线数据结构 % 轮廓线初始为一条从x0到xW高度为0的线段 skyline struct(x, 0, width, W, height, 0); % 简单起见用结构数组表示 % 更高效的实现可能用两个数组x坐标数组和对应的高度数组。 % 4. 定义已放置零件的信息 placed []; % 每行记录一个已放置零件[x, y, w, h]4.2 核心函数基于轮廓线的可放置位置查找function [best_x, best_y, best_rot] find_best_position(part_width, part_height, skyline, W, H, gap, placed) % 寻找放置给定零件考虑旋转的最佳左下角位置BL规则 best_y Inf; best_x Inf; best_rot 0; % 0-不旋转1-旋转 candidate_rotations [part_width, part_height; part_height, part_width]; % 两种朝向 for rot 1:2 w candidate_rotations(rot, 1) gap; % 考虑间隙 h candidate_rotations(rot, 2) gap; % 遍历轮廓线的每一段 for i 1:length(skyline) seg_x skyline(i).x; seg_width skyline(i).width; seg_height skyline(i).height; % 如果这段轮廓的宽度足够放置当前零件 if seg_width w candidate_x seg_x; candidate_y seg_height; % 检查从(candidate_x, candidate_y)放置一个w*h的矩形是否可行 % 需要满足1. 右边界不超出板材 2. 不与已放置零件重叠 if candidate_x w W candidate_y h H % 快速重叠检测与已放置零件检查 overlap false; for j 1:size(placed, 1) px placed(j, 1); py placed(j, 2); pw placed(j, 3); ph placed(j, 4); % 判断矩形是否重叠考虑间隙 if ~(candidate_x w px || candidate_x px pw || ... candidate_y h py || candidate_y py ph) overlap true; break; end end if ~overlap % 按照BL规则选择y最小的y相同时x最小的 if candidate_y best_y || (candidate_y best_y candidate_x best_x) best_y candidate_y; best_x candidate_x; best_rot rot - 1; % 转换为0/1 end end end end % 还需要考虑从该轮廓段中间某点开始放置的情况如果零件宽度小于段宽 % 更完善的实现需要检查段内每个可能的起始x位置通常按已放置零件的右边界作为候选x end end if isinf(best_y) best_x -1; best_y -1; best_rot -1; % 表示无法放置 end end这个find_best_position函数是算法的引擎。它遍历轮廓线的每一段对于零件的两种旋转方式尝试将零件的左下角对齐到轮廓段的左上角然后检查放置是否合法不超界、不重叠。在所有合法位置中按照BL规则挑选最优。4.3 主循环与轮廓线更新% 主算法按给定顺序放置零件 order randperm(num_parts); % 随机顺序这是最简单的策略 for idx 1:num_parts part_id order(idx); w0 part_list(part_id, 1); h0 part_list(part_id, 2); [x, y, rot] find_best_position(w0, h0, skyline, W, H, gap, placed); if x 0 % 找到了可放置位置 if rot 1 w_placed h0; h_placed w0; else w_placed w0; h_placed h0; end % 记录已放置零件 placed [placed; x, y, w_placed, h_placed]; % 更新轮廓线 - 这是算法中最复杂的部分之一 % 1. 在x到xw_placed的区间内轮廓线高度被提升到yh_placed % 2. 可能需要分割、合并轮廓线段 skyline update_skyline(skyline, x, y, w_placed, h_placed); else % 如果当前板材放不下可以开始新的一张板材在优化板材张数时 fprintf(零件 %d 无法放入当前板材考虑启用新板。\n, part_id); % 重置skyline和placed开始新板计算 % skyline struct(x, 0, width, W, height, 0); % placed []; % 然后将当前零件放入新板... % 注意这里涉及到多张板材的全局优化逻辑会更复杂。 end end % 计算当前板材利用率 total_area sum(placed(:,3) .* placed(:,4)); utilization total_area / (W * H); fprintf(板材利用率: %.2f%%\n, utilization * 100);4.4 高级策略多顺序迭代与可视化一次随机顺序的结果具有偶然性。我们需要多次尝试。num_trials 100; % 尝试100种不同的顺序 best_utilization 0; best_placed []; best_order []; for trial 1:num_trials % 生成顺序可以纯随机也可以基于规则扰动如按面积排序后随机交换 if rand() 0.5 order randperm(num_parts); else % 按面积降序排序后随机交换相邻元素产生轻微扰动 [~, area_order] sort(part_list(:,1) .* part_list(:,2), descend); order area_order; for k 1:floor(num_parts/10) i randi(num_parts-1); order([i, i1]) order([i1, i]); end end % 运行一次BL排样算法需重置板材状态 [util, placed_result] run_bl_algo_for_one_board(order, part_list, W, H, gap); if util best_utilization best_utilization util; best_placed placed_result; best_order order; end end fprintf(经过 %d 次尝试最佳利用率为: %.2f%%\n, num_trials, best_utilization*100); % 可视化最佳排样结果 figure; hold on; rectangle(Position, [0, 0, W, H], EdgeColor, k, LineWidth, 2); % 板材边框 colors lines(size(best_placed, 1)); % 生成不同颜色 for i 1:size(best_placed, 1) rect best_placed(i, :); rectangle(Position, [rect(1), rect(2), rect(3), rect(4)], ... FaceColor, colors(i,:), EdgeColor, w, LineWidth, 0.5); % 可以在矩形中心标注零件编号 text(rect(1)rect(3)/2, rect(2)rect(4)/2, num2str(i), ... HorizontalAlignment, center, Color, k); end axis equal; xlim([0, W]); ylim([0, H]); title(sprintf(最佳排样方案 - 利用率: %.2f%%, best_utilization*100)); xlabel(宽度); ylabel(高度); hold off;run_bl_algo_for_one_board函数封装了单次BL算法的完整流程包括轮廓线初始化和更新。通过循环多次我们就能以较高的概率找到一个令人满意的排样方案。可视化步骤至关重要它能直观地检查排样结果是否合理有无明显重叠或异常。5. 从竞赛到实战工程化扩展与常见陷阱竞赛模型是高度简化的而真实的工业切割问题要复杂得多。理解这些扩展点不仅能提升竞赛论文的深度也是将算法应用于实际的关键。5.1 实际工程中的复杂约束多规格板材 原材料可能有多种宽度和长度需要同时选择板材规格和排样方案成本模型更复杂。一刀切约束 如果必须满足一刀切上述BL算法生成的排样可能无效。需要专门设计满足一刀切约束的排样算法或者在后处理阶段将普通排样方案分解成一刀切切割步骤这本身就是一个NP难问题。板材缺陷与余料管理 板材上可能有孔洞、锈蚀等缺陷区域不能使用。排样时需要避开这些区域。此外切割后产生的较大余料可能作为小板材继续使用这就需要建立“余料库”并进行动态管理。切割路径优化 零件排样确定后切割头如何移动才能总路径最短、耗时最少这又是一个旅行商问题TSP的变种。多工艺混合 一块板材上可能同时有激光切割、冲压、钻孔等多种工艺需求需要考虑不同工艺的顺序和相互影响。5.2 算法实现中的性能陷阱与优化重叠检测的效率 在find_best_position函数中我们用了遍历所有已放置零件的朴素方法来检测重叠。当零件数量很多时这会成为性能瓶颈。优化方法包括空间分区 将板材划分为网格或使用四叉树等数据结构只检查可能与新矩形相交的区域内的零件。扫描线算法 维护一个按x或y坐标排序的矩形边列表可以高效地检测矩形集合中是否有重叠。轮廓线更新的正确性update_skyline函数的实现需要非常小心。必须正确处理新矩形覆盖部分轮廓段、分割轮廓段、以及合并相邻同高段的所有情况。一个错误的更新会导致后续放置位置判断错误。建议用详细的单元测试来验证这个函数例如放置几个特定位置的矩形然后打印并人工检查轮廓线变化。随机策略的改进 纯随机排列randperm效率较低。可以采用更智能的搜索策略模拟退火 以零件顺序为状态利用率为能量。通过交换、逆序等操作产生新状态以一定概率接受更差的状态以避免陷入局部最优。遗传算法 种群中的个体是零件顺序通过选择保留高利用率个体、交叉如OX交叉、变异随机交换来进化。禁忌搜索 记录近期搜索过的顺序避免循环。5.3 竞赛论文写作与结果分析要点如果你在为数学建模竞赛解题除了写出代码还需要在论文中清晰呈现模型对比 不要只给出一个算法。可以尝试多种排序规则面积降序、宽度降序、综合评分对比它们的利用率。甚至可以简单提一下精确MILP模型并说明其在大规模问题上的局限性从而引出启发式算法的必要性。灵敏度分析 改变板材尺寸、零件数量、间隙大小观察利用率的变化趋势。例如“当零件平均面积减小时利用率会下降因为小零件更难紧密填充缝隙”。可视化与示例 一定要附上排样效果图。对于最优方案可以用表格列出每个零件的具体坐标和旋转状态。这比单纯一个利用率数字有说服力得多。算法复杂度分析 简要分析你的BL算法的时间复杂度。例如对于n个零件每次放置需要扫描轮廓线假设平均线段数为m并进行重叠检测最坏O(n)所以单次放置是O(m*n)。总复杂度约为O(n^2 * m)。通过优化数据结构可以降低。工业零件切割优化是一个连接数学、计算机科学和工业工程的经典问题。通过华数杯这道赛题我们不仅学习了一个具体的优化模型和算法更掌握了一套解决复杂现实问题的思路定义问题、抽象模型、设计算法、实现验证、分析优化。从简单的BL算法到融合元启发式策略从单一的板材到考虑多约束的复杂系统这个问题的深度和广度足以让你持续探索很久。最关键的是当你看到自己编写的程序生成那个几乎铺满板材的排样图时那种用代码和逻辑解决实际问题的成就感正是数学建模和算法工程最大的魅力所在。
返回列表