【数学建模】【matlab】二维矩形排样代码实现

题目来源及衍生背景

题目来源于2021年mathorcup数学建模比赛D题第一题, 最初时间紧迫,采用randchoose()函数随机选取一款订单,有点类似于蚁群算法,只是缺少了“信息素”这个概念,没有一种回溯的效率提升。但是其由于原题中数量过于庞大,第一题采用蚁群算法计算以及调试时间过长,在比赛期间心情紧张可能导致得不偿失,因此最终选择将其简化。

并且在长里为了控制宽度一致,每行上放的都是同一种订单。

如果希望对订单要求比较高,是不规则的排样,并且不能保证每行放置的都是同一种订单,那可以采用“最低水平面”方法,可以关注我,我写的“最低水平面算法”文章。

我在代码中加入了详细的注释,所以原理部分写的不是很详细,大家可以抓住“先排长,再排宽”这句话直接看代码部分。

二维矩形排样的实现

算法原理

简单理解成先长里排到排不下,再对宽进行排件,并且注意每行放置的都是同一种订单,如下图所示:

这个图有点问题,应该吧LSj2和WSj1的位置互换
在这里插入图片描述
首先对1 --> 2这个过程进行遍历,在十种原料的条件下,遍历五种订单中放的下该件的情况,放置后再对宽进行排布。

最后计算余料的时候,可以完整的得到左边和下边的两块余料。

重点难点

首先,这个图有点问题,应该吧LSj2和WSj1的位置互换

其中有两个难以快速理解的点,大家可以先记着,看到的时候再回来看。

ws2:在上图中为余料2在长的方向上边的长度

ls1:在上图中为余料在宽的方向上边的长度

其次,47行开始为原题中限制余料规格的要求,大家可以根据自己题目的要求进行更改

算法源码

function mathorcup_1()
%% 数据的导入与预定义
product = xlsread('附件3_4.xlsx', '订单', 'B2 : G16'); % 长度、宽度、需求量、浮动比例、种类
material = xlsread('附件3_4.xlsx', '原料', 'B2 : E11'); % 长度、宽度、库存
PLAN = cell(10, 6); % 存放计划切割方案的元组
plan = zeros(10, 10); %
%% 二维矩形的排样
for j = 1 : 10 % 对十种原料进行遍历
    % 对长进行循环
    if(material(j, 1) > min(product(1 : 5, 1))) % 如果原料的长>卷料订单中长的最小值
        
        i_list = find(product(1 : 5, 1) < material(j, 1)); % 保存满足放置条件的订单的位置
        wsl = material(j, 2); % 原料剩余可用的宽度
        lsl = material(j, 1); % 原料剩余可用的长度
        num_kind_width = zeros(1, 5); % 5种订单宽的切割方案
        num_kind_length = zeros(1, 5); % 5种订单长的切割方案
        % 对宽进行循环
        while(wsl > min(product(1 : 5, 2))) % 当原料剩余可用的宽度 > 卷料订单中宽的最小值
            
            i = randchoose(i_list, 1); % 随机从满足放置条件的订单中选一个
            if(wsl - product(i, 2) < 0) % 如果在放置后,卷料剩余可用的宽度仍大于零则继续
                continue
            end
            % 当某一个节点之后卷料剩余可用宽度小于零执行以下内容
            wsl = wsl - product(i, 2); % 更新原料剩余可用宽度
            num_kind_width(i) = num_kind_width(i) + 1; % 更新原料剩余可用长度
            num_kind_length(i) = fix(material(j, 1) / product(i, 1)); % 计算长上放置的订单数量
            % num_kind_width_length存放格式:1~5:五种订单宽的数量,6~10:五种订单长的数量
            num_kind_width_length = [num_kind_width, num_kind_length]; % 每种原料中长、宽放置的订单数量
        end
        % 将第j种原料的五种订单的各个数量存放进plan数组
        % plan存放格式:第j行:第几种原料,每一行后面的10个数:第几种原料放置各个订单的长和宽的数量
        for k = 1 : 10
            plan(j, k) = num_kind_width_length(k);
        end
        
        ws2 = material(j, 1) - max(plan(j, 6 : 10) .* product(1 : 5, 1)'); % max()求得原料切割订单后与余料的一个切面
        ls2 = material(j, 2); % 原料的宽度
        ls1 = ls1 - ws2;
        
        % 长度余量
        S_Product = 0;
        for n = 1 : 5
            S_Product = S_Product + plan(j, n) * plan(j, n + 5) * product(n, 6);
        end
        
        % 以下为原题中判断余料是否满足标准的条件设置,可以根据题意进行更改
        S_surplus = 0;
        if(wsl > 100 && lsl > 50000)
            S_surplus = S_surplus + wsl * lsl;
        end
        if(ws2 > 2000 && ls2 > 1000)
            S_surplus = Surplus + ws2 * ls2;
        end
        R = (S_surplus + S_Product) / material(j, 4);
        % 数据的输出
        PLAN{j, 6} = R;
        for n = 1 : 5
            PLAN{j, n} = [num_kind_width_length(n), num_kind_width_length(n + 5)];
        end
    end
end
end
  • 6
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
以下是一个简单的二维排样代码示例: ```matlab clc clear all % 定义物品尺寸和数量 item_size = [10, 20; 15, 25; 5, 15; 10, 10; 20, 30]; item_num = [3, 2, 4, 5, 1]; % 定义板材尺寸和数量 board_size = [100, 200]; board_num = 5; % 初始化排样结果 layout_result = zeros(size(item_size, 1), 3); % 循环排样每个物品 for i = 1:size(item_size, 1) % 判断当前物品是否已排满 if item_num(i) == 0 continue; end % 循环板材进行排样 for j = 1:board_num % 判断当前板材是否已排满 if sum(layout_result(layout_result(:, 1) == j, 3)) == board_size(1) * board_size(2) continue; end % 在当前板材上尝试排放当前物品 [x, y, r] = pack_item(item_size(i, :), layout_result(layout_result(:, 1) == j, :)); % 判断是否排放成功 if r == 0 % 排放成功,记录排样结果,更新物品数量 layout_result(size(layout_result, 1) + 1, :) = [j, x, y]; item_num(i) = item_num(i) - 1; break; end end end % 输出排样结果 for i = 1:size(layout_result, 1) fprintf("Item %d: (%d, %d) on board %d\n", i, layout_result(i, 2), layout_result(i, 3), layout_result(i, 1)); end % 定义排放物品的函数 function [x, y, r] = pack_item(size, layout) % 初始化排放位置和旋转角度 x = 0; y = 0; r = 0; % 循环尝试不同位置和角度进行排放 for i = 1:2 for j = 1:2 for k = 0:1 % 根据旋转角度选择物品长宽 if k == 0 w = size(1); h = size(2); else w = size(2); h = size(1); end % 计算当前排放位置和旋转角度下的物品边界 left = layout(:, 2) + x; right = left + w; bottom = layout(:, 3) + y; top = bottom + h; % 判断当前位置是否可行 if max(right) <= 200 && max(top) <= 100 && min(left) >= 0 && min(bottom) >= 0 % 可行,返回排放位置和旋转角度 r = k; return; end % 位置不可行,尝试下一个位置和角度 y = y + (1 - 2 * j) * h; end y = 0; x = x + (1 - 2 * i) * w; end x = 0; end end ``` 该代码实现了一个简单的二维排样算法,可以排放多个不同尺寸的物品在多张相同尺寸的板材上,以最小化板材的浪费。算法采用贪心策略,每次选择最先能排放的物品和板材进行排样,直到所有物品都排放完成。在排放物品时,通过循环尝试不同位置和角度进行排放,找到可行的位置后记录排放位置和旋转角度,并返回给主程序。主程序将排放位置和旋转角度记录在排样结果中,并更新物品数量。最终输出所有物品的排放位置和板材编号。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值