2024年MathorCup(妈妈杯)数学建模C题(物流网络分拣)助攻论文&支撑材料.doc

 本博客下载链接包含修改的word版本, 可免费下载阅览学习, 也可作为数学建模相关课程作业修改上交:

链接:https://pan.baidu.com/s/1HxzDk3q0p6y2xpuJyxPgvw?pwd=qtnc

提取码:qtnc

        物流网络分拣中心货量预测及人员排班优化问题是一个综合性的研究问题,本文通过精准预测分拣中心的货量需求,并基于此预测合理安排人力资源,以提高物流效率并降低运营成本。

        针对问题一,我们利用历史货量数据和物流网络配置信息,预测未来30天内每个分拣中心每天及每小时的货量。对数据进行清洗以及整合后,我们采用了长短期记忆网络(LSTM)和自回归积分滑动平均模型(ARIMA)两种方法。根据LSTM模型能够捕捉时间序列数据中的长期依赖关系的也特性来预测日货量,使用ARIMA模型则适用于短期预测用来预测小时货量,最终将预测结果填入结果表1. csv与结果2. csv中。

     ​​​​​​​   针对问题二,分析分拣中心之间运输线路变化对货量预测的影响,首先我们重新评估这些变化对货量预测的影响,绘制有向图并识别出发生变化的分拣中心分别为:SC8SC5SC4SC47SC15SC51SC10SC25SC7SC9SC60,并计算这些路线的总货量,然后对其进行归一化后计算货量的变化比例并分配到对应的路线上,根据货物分配的比例计算出修正后的路线变化率,将变化率乘以问题一的预测结果进而得出到修正后的货量预测,最终将修正后的预测结果填入结果表3.csv与结果4. csv中。

     ​​​​​​​   针对问题三,在确保货量得到有效处理的基础上,考虑最小化总人天数,同时保持小时人效的均衡,因此建立了最小化总人天数整数线性规划模型,其中决策变量包括每个分拣中心每个班次的正式工和临时工出勤人数,同时设置满足货量处理完成、正式工优先使用、实际小时人效均衡等约束条件。通过线性规划求解器求解该模型,最终得到每个分拣中心每个班次的最优出勤人数,并将优化后的结果填入结果表5. csv中。

     ​​​​​​​   针对问题四,对特定分拣中心的排班问题进行了深入研究。以SC1分拣中心为例,并基于问题二的预测结果,建立了正式工及临时工的班次出勤计划模型。在问题三模型的基础上,以最小化正式工与临时工的人数为总目标函数,设置考虑每名正式工的出勤率不超过85%,且连续出勤天数不超过7天的约束,使用线性规划求解器进行求解,最终得出,并将优化后的结果填入结果表6.csv中。

     ​​​​​​​   最后分析了模型的优缺点并,根据本文所建立的预测以及规划模型,为物流网络分拣中心的货量预测和人员排班优化问题提供了有效的解决方案,在保证货量得到有效处理的同时,优化人力资源的分配,从而提高物流网络的整体效率和降低运营成本。

关键词:货量预测;ARIMA-LSTM;排班优化;线性规划;整数规划;多目标规划;

1. 问题一的分析

第一步分析:首先,我们需要明确货量预测的目标和约束条件。在本问题中,目标是预测57个分拣中心未来30天每天及每小时的货量。这涉及到两个不同时间尺度的预测问题:日货量预测和小时货量预测。这两个预测任务具有不同的特点和需求,因此需要采用不同的模型和方法。

第二步分析:对于日货量预测,由于货量数据可能具有时间序列的依赖性和长期趋势,我们可以考虑使用长短期记忆网络(LSTM)这种深度学习模型。LSTM模型能够捕捉序列数据中的长期依赖关系,适合处理具有时间序列特性的货量数据。通过训练LSTM模型,全糖奶茶屋我们可以利用历史货量数据来预测未来每天的货量。

第三步分析:对于小时货量预测,由于时间尺度更短,货量变化可能受到更多随机因素的影响,且可能存在周期性模式。因此,我们可以考虑使用自回归积分滑动平均模型(ARIMA)进行预测。ARIMA模型能够捕捉数据的趋势、季节性和随机性,适合处理短期内的时间序列预测问题。通过选择合适的ARIMA模型参数,我们可以对每小时的货量进行滚动预测。

第一小问部分MATLAB代码展示:

clc
clear
close all
load data1
%%
result=[]
data=[]
for i=1:57
    data(:,i)=table2array(sortedData1{i}(:,3))
end
%%
for j=1:57
    % 序列的前485个用于训练,后10个用于验证神经网络,然后往后预测10个数据。
    dataTrain = data(1:100,j)';    %定义训练集
    dataTest = data(101:122,j)';    %该数据是用来在最后与预测值进行对比的
    % 数据预处理
    mu = mean(dataTrain);    %求均值
    sig = std(dataTrain);      %求均差
    dataTrainStandardized = (dataTrain - mu) / sig;
    % 输入的每个时间步,LSTM网络学习预测下一个时间步,这里交错一个时间步效果最好。
    XTrain = dataTrainStandardized(1:end-1);
    YTrain = dataTrainStandardized(2:end);
    % 一维特征lstm网络训练
    numFeatures = 1;   %特征为一维
    numResponses = 1;  %输出也是一维
    numHiddenUnits = 100;   %创建LSTM回归网络,指定LSTM层的隐含单元个数200。可调
    layers = [ ...
        sequenceInputLayer(numFeatures)    %输入层
        lstmLayer(numHiddenUnits)  % lstm层,如果是构建多层的LSTM模型,可以修改。
        fullyConnectedLayer(numResponses)    %为全连接层,是输出的维数。
        regressionLayer];      %其计算回归问题的半均方误差模块 。即说明这不是在进行分类问题。
    
    %指定训练选项,求解器设置为adam, 1000轮训练。
    %梯度阈值设置为 1。指定初始学习率 0.01,在 125 轮训练后通过乘以因子 0.2 来降低学习率。
    options = trainingOptions('adam', ...
        'MaxEpochs',300, ...
        'GradientThreshold',1, ...
        'InitialLearnRate',0.01, ...
        'LearnRateSchedule','piecewise', ...%每当经过一定数量的时期时,学习率就会乘以一个系数。
        'LearnRateDropPeriod',400, ...      %乘法之间的纪元数由“ LearnRateDropPeriod”控制。可调
        'LearnRateDropFactor',0.15, ...      %乘法因子由参“ LearnRateDropFactor”控制,可调
        'Verbose',0) %如果将其设置为true,则有关训练进度的信息将被打印到命令窗口中。默认值为true。
    net = trainNetwork(XTrain,YTrain,layers,options);
    net = predictAndUpdateState(net,XTrain);  %将新的XTrain数据用在网络上进行初始化网络状态
    [net,YPred] = predictAndUpdateState(net,YTrain(end));  %用训练的最后一步来进行预测第一个预测值,给定一个初始值。这是用预测值更新网络状态特有的。
    % 进行用于验证神经网络的数据预测(用预测值更新网络状态)
    for i = 2:52  %从第二步开始,这里进行20次单步预测(10为用于验证的预测值,10为往后预测的值。一共20个)
        [net,YPred(:,i)] = predictAndUpdateState(net,YPred(:,i-1),'ExecutionEnvironment','cpu');  %predictAndUpdateState函数是一次预测一个值并更新网络状态
    end
    % 验证神经网络
    YPred1 = sig*YPred + mu;      %使用先前计算的参数对预测去标准化。
    rmse = sqrt(mean((YPred1(1:22)-dataTest).^2)) ;     %计算均方根误差 (RMSE)。
    result(:,j)=YPred1(23:end)'
end
%%
% 循环绘制前30列数据的图表
figure;
for i = 1:30
    subplot(5, 6, i);
    plot(data(1:end,i))   %先画出前面485个数据,是训练数据。
    hold on
    idx = 123:(122+30);   %为横坐标
    plot(idx,result(:,i),'.-')  %显示预测值
    hold off
    xlabel("Time")
    ylabel("Case")
    title("Forecast")
    legend(["Observed" "Forecast"])
end
figure;
for i = 31:57
    subplot(5, 6, i-30);
    plot(data(1:end,i))   %先画出前面485个数据,是训练数据。
    hold on
    idx = 123:(122+30);   %为横坐标
    plot(idx,result(:,i),'.-')  %显示预测值
    hold off
    xlabel("Time")
    ylabel("Case")
    title("Forecast")
    legend(["Observed" "Forecast"])
end
%%
center_write=[]
date_write=[]
result_write=[]
% 指定要保存的Excel文件名
filename = '结果表1.csv';
% 将变量名称写入 Excel 文件的第一列
variable_names = {'分拣中心','日期','货量'}
writecell(variable_names,filename);
% 开始日期和结束日期
startDate = datetime(2023, 12, 1);
endDate = datetime(2023, 12, 30);
% 生成时间数据
timeData = startDate:endDate;
% 将日期时间数据转换为指定格式的字符串
timeString = datestr(timeData, 'yyyy/mm/dd');
date=cellstr(timeString)
for k=1:57
    center=sortedData1{k}(1:30,1)
    center=table2cell(center)
    center_write=[center_write;center]
    date_write=[date_write;date]
    result_write=[result_write;result(:,k)]
end
% 确定要追加数据的起始位置,即下一个空行
% 将数据写入 Excel 文件的第一列,追加到现有数据的下方
xlswrite(filename, [center_write, date_write, num2cell(result_write)], '结果表1', 'A2');

2. 问题二的分析

第三步分析:首先,我们需要对附件三和附件四中的数据进行匹配,以识别出发生变化的路线。变化路线指的是在两个附件中,从起始点到分拣中心的路径存在差异的路线。通过比较这些路线,我们可以确定哪些路线发生了调整或变更。接下来,我们需要计算这些变化路线的总货量。总货量是指每个变化路线上所有货物的总量,这是评估路线变化对整体物流影响的关键指标。通过对每条变化路线的货量进行汇总,我们可以得到变化路线的总货量数据。

第二步分析:以到达分拣中心为参考点,我们需要将第一步中计算出的总货量按照不同的比例分配到对应的路线上。这里的比例分配可以根据实际情况进行设定,比如根据路线的长度、运输效率、成本等因素进行综合考虑。全糖奶茶屋完成货量分配后,我们需要重新计算总货量的变化率。变化率是指新的货量分配方案与原始货量分配方案之间的差异程度,它反映了路线变化对整体货量分布的影响。通过比较新旧方案的货量数据,我们可以计算出变化率的具体数值。

第三步分析:将第二步中计算出的变化率与问题一中的预测结果相乘,作为修正后的预测结果。问题一中的预测结果可能是基于原始路线和货量分布得出的,全糖奶茶屋而路线变化可能导致这些预测结果不再准确。因此,我们需要根据变化率对预测结果进行修正,以反映实际情况的变化。

第二小问部分MATLAB代码展示:

clc
clear
close all
load data2
%%
result=[]
data=[]
for i=1:57
    data(:,i)=table2array(sortedData2{i}(:,4))
end
%%
for j=1:57
    % 导入数据
    y = data(:,j); % 将 'your_data' 替换为你的实际数据
    
    % 创建ARIMA模型
    Mdl = arima(24,0,0); 
    
    % 拟合模型
    EstMdl = estimate(Mdl, y);
    
    % 预测未来720期数据
    numPeriods = 720;
    [YF, YMSE] = forecast(EstMdl, numPeriods, 'Y0', y);
    result(:,j)=YF
end
%% 
% 创建一个逻辑索引,找出所有小于0的元素
negative_indices = result < 0;
% 将小于0的元素置为0
result(negative_indices) = 0;
% 循环绘制前30列数据的图表
figure;
for i = 1:30
    subplot(5, 6, i);
    plot(data(1:end,i))   %先画出前面485个数据,是训练数据。
    hold on
    idx = 721:(720+720);   %为横坐标
    plot(idx,result(:,i),'.-')  %显示预测值
    hold off
    xlabel("Time")
    ylabel("Case")
    title("Forecast")
    legend(["Observed" "Forecast"])
end
figure;
for i = 31:57
    subplot(5, 6, i-30);
    plot(data(1:end,i))   %先画出前面485个数据,是训练数据。
    hold on
    idx = 721:(720+720);   %为横坐标
    plot(idx,result(:,i),'.-')  %显示预测值
    hold off
    xlabel("Time")
    ylabel("Case")
    title("Forecast")
    legend(["Observed" "Forecast"])
end
%%
center_write=[]
date_write=[]
result_write=[]
hour_write=[]
% 指定要保存的Excel文件名
filename = '结果表2.csv';
% 将变量名称写入 Excel 文件的第一列
variable_names = {'分拣中心','日期','小时','货量'}
writecell(variable_names,filename);
% 开始日期和结束日期
startDate = datetime(2023, 12, 1);
endDate = datetime(2023, 12, 30);
% 生成时间数据
timeData = startDate:endDate;
% 将日期时间数据转换为指定格式的字符串
timeString = datestr(timeData, 'yyyy/mm/dd');
date=cellstr(timeString)
% 初始化一个空数组来存储扩展后的日期
expanded_date = {};
% 循环遍历每个日期
for i = 1:30
    hour_write=[hour_write;(0:23)']
end
% 初始化一个空数组来存储扩展后的日期
expanded_hour = {};
% 循环遍历每个日期
for i = 1:numel(date)
    % 将当前日期重复24次
    repeated_date = cellstr(repmat(date{i}, 24, 1));
    
    % 将重复后的日期追加到数组中
    expanded_date = [expanded_date; repeated_date];
end

date_write=[]
for k=1:57
    date_write = [date_write; expanded_date];
end

hour_write1=[]
for k=1:57
    hour_write1=[hour_write1;hour_write]
end

for k=1:57
    center=sortedData2{k}(1:720,1)
    center=table2cell(center)
    center_write=[center_write;center]
    result_write=[result_write;result(:,k)]
    % 将重复后的日期追加到数组中
end
% 确定要追加数据的起始位置,即下一个空行
% 将数据写入 Excel 文件的第一列,追加到现有数据的下方
xlswrite(filename, [center_write, date_write,num2cell(hour_write1), num2cell(result_write)], '结果表2', 'A2');

3. 问题三的分析

第一步分析:理解问题背景和目标,在这个问题中,我们面临的是一个典型的物流分配问题,具体来说,是如何在一个分拣系统中合理安排人力资源以处理每天的货量。问题背景指出,存在57个分拣中心,每个中心每天需要处理一定量的货物,而每天分为6个班次。每个员工每天只能工作一个班次,且正式工和临时工的小时人效不同。我们的目标是在确保每天的货量得到处理的前提下,最小化总人天数,同时尽量保持小时人效的均衡。

第二步分析:为了解决这个问题,我们需要建立一个整数线性规划模型。模型的决策变量为出勤人数。目标函数是最小化总人天数,即所有决策变量的总和。约束条件包括:每个分拣中心每天的货量必须得到处理,这意味着每个中心每天的班次货量之和必须等于当天的总货量。每个分拣中心有60名正式工,这是每个中心的最大员工数。优先使用正式工,这意味着在满足货量处理的前提下,应尽可能多地分配正式工。每天的实际小时人效尽量均衡,避免某些班次人效过高而其他班次人效过低。所有决策变量必须是整数,因为员工人数不能是小数。

第三步分析:在建立了数学模型之后,我们需要使用适当的算法来求解这个模型。在MATLAB中,我们可以使用intlinprog函数来求解整数线性规划问题。首先,我们需要根据问题规模创建决策变量、目标函数系数、约束条件等。然后,我们将这些信息输入到intlinprog函数中,并设置相应的参数,如整数约束intcon和变量的上下界lb和ub。求解完成后,我们得到每个分拣中心每个班次的出勤人数,这些人数是整数,并且满足所有的约束条件。最后,我们根据这个优化结果来安排实际的人员分配,确保货量得到有效处理,同时达到最小化人天数的目标。

第三小问部分MATLAB代码展示:

clc
clear
close all
load data
load data2
%% 
xc = ones(57, 30, 6);
yc = ones(57, 30, 6);
% 将矩阵转换为一列
xc1 = reshape(xc, [], 1);
yc1 = reshape(yc, [], 1);

% 定义目标函数系数
f = [xc1;yc1];

% 定义变量类型和上下界
intcon = 1:length(f);
lb = [10*ones(length(f)/2, 1);zeros(length(f)/2, 1)];
ub = [60*ones(length(f)/2, 1);inf*ones(length(f)/2, 1)];

% 定义约束矩阵和约束边界
%约束1:每天的货量处理完成
% 确定矩阵和子矩阵的尺寸
b1=a
rows = 1710;
cols = 20520;
blockSize = 6;
A1 = zeros(rows, cols);
fillValueX = 25*8;
fillValueY = 20*8;
for i = 1:rows
    % 计算当前行的填充位置
    startXIndex = mod((i-1)*blockSize, cols) + 1;
    endXIndex = startXIndex + blockSize - 1;
    startYIndex = cols/2 + startXIndex;
    endYIndex = startYIndex + blockSize - 1;   
    % 如果索引超出范围,循环它回到矩阵起始位置
    if endXIndex > cols/2
        overIndex = endXIndex - cols/2;
        A1(i, startXIndex:cols/2) = fillValueX;
        A1(i, 1:overIndex) = fillValueX;
        A1(i, startYIndex:cols) = fillValueY;
        A1(i, cols/2+1:cols/2+overIndex) = fillValueY;
    else
        A1(i, startXIndex:endXIndex) = fillValueX;
        A1(i, startYIndex:endYIndex) = fillValueY;
    end
end


%约束2:每个分拣中心有60名正式工
b2=60*ones(1710,1)
rows = 1710;
cols = 20520;
blockSize = 6;
A2 = zeros(rows, cols);
fillValueX = 1;
fillValueY = 0;
for i = 1:rows
    % 计算当前行的填充位置
    startXIndex = mod((i-1)*blockSize, cols) + 1;
    endXIndex = startXIndex + blockSize - 1;
    startYIndex = cols/2 + startXIndex;
    endYIndex = startYIndex + blockSize - 1;   
    % 如果索引超出范围,循环它回到矩阵起始位置
    if endXIndex > cols/2
        overIndex = endXIndex - cols/2;
        A2(i, startXIndex:cols/2) = fillValueX;
        A2(i, 1:overIndex) = fillValueX;
        A2(i, startYIndex:cols) = fillValueY;
        A2(i, cols/2+1:cols/2+overIndex) = fillValueY;
    else
        A2(i, startXIndex:endXIndex) = fillValueX;
        A2(i, startYIndex:endYIndex) = fillValueY;
    end
end

%合并约束条件
A=[-A1;A2]
b=[-b1;b2]
% 设置选项以保存迭代信息
options = optimoptions(@intlinprog,'display','iter','OutputFcn',@savemilpsolutions,'PlotFcn',@optimplotmilp);
% 使用CPLEX求解整数规划问题
[x, fval, exitflag, output] = intlinprog(f, intcon, A, b, [], [], lb, ub, options);

% 输出结果
disp('最优解:');
disp(x);
disp('目标函数值:');
disp(fval);
disp('退出标志:');
disp(exitflag);

%% 
center_write=[]
date_write=[]
result_write=[]
banci_write=[]
banci={'00:00-08:00','05:00-13:00','08:00-16:00','12:00-20:00','14:00-22:00 ','16:00-24:00'}
% 重复元胞数组1710次
banci_repeated = (repmat(banci, 1, 1710))';
banci_write=banci_repeated
% 指定要保存的Excel文件名
filename = '结果表5.csv';
% 将变量名称写入 Excel 文件的第一列
variable_names = {'分拣中心','日期','班次','正式工人数','临时工人数'}
% 开始日期和结束日期
startDate = datetime(2023, 12, 1);
endDate = datetime(2023, 12, 30);
% 生成时间数据
timeData = startDate:endDate;
% 将日期时间数据转换为指定格式的字符串
timeString = datestr(timeData, 'yyyy/mm/dd');
date=cellstr(timeString)
% 初始化一个空数组来存储扩展后的日期
expanded_date = {};
% 循环遍历每个日期
for i = 1:numel(date)
    % 将当前日期重复24次
    repeated_date = cellstr(repmat(date{i}, 6, 1));  
    % 将重复后的日期追加到数组中
    expanded_date = [expanded_date; repeated_date];
end

date_write=[]
for k=1:57
    date_write = [date_write; expanded_date];
end

for k=1:57
    center=sortedData2{k}(1:180,1)
    center=table2cell(center)
    center_write=[center_write;center]
    % 将重复后的日期追加到数组中
end
z1=num2cell(x(1:10260))
z2=num2cell(x(10261:end))
% 确定要追加数据的起始位置,即下一个空行
% 将数据写入 Excel 文件的第一列,追加到现有数据的下方
xlswrite(filename, [variable_names;center_write, date_write, banci_write,z1,z2], '结果表5', 'A1');

4. 问题四的分析

第一步分析:问题定义与需求分析,我们首先需要清晰地定义问题的范围和目标。对于分拣中心SC60,问题的核心是在未来30天内,如何安排200名正式工和临时工的班次,以完成每天的货量处理任务。我们的目标是在确保货量得到处理的基础上,最小化总人天数,同时保持正式工的出勤率均衡,并满足每位正式工的出勤率不超过85%和连续出勤天数不超过7天的约束。在需求分析阶段,我们需要收集相关的数据,包括每天的货量、正式工和临时工的工作效率、以及班次的安排等。此外,我们还需要了解正式工的出勤情况,以便在模型中准确地反映每位员工的出勤率和连续出勤天数的约束。

第二步分析:我们将问题转化为数学模型,明确决策变量、目标函数和约束条件。决策变量表示班次的出勤情况,目标函数是最小化总人天数,同时考虑正式工的出勤率。在构建模型时,我们还需要考虑模型的求解效率和可行性,确保模型可以在合理的时间内求解,并且能够得到可行解。

第三步分析:在模型构建完成后,我们使用适当的优化算法来求解模型。在求解过程中,我们需要调整算法参数,如迭代次数、学习率等,以获得更好的解。求解完成后,我们对结果进行分析,确保解满足所有约束条件,并且在实际操作中是可行的。如果解满足所有要求,我们可以将其转化为具体的排班计划,并在分拣中心SC60实施。在实施过程中,我们需要监控排班计划的效果,并根据实际情况进行必要的调整。

第四小问部分MATLAB代码展示:

clc
clear
close all
load data
%%
%约束1:完成货量处理
b1=a
A1 = zeros(30, 36180);
xindex=1
yindex=36001
for i = 1:30
    A1(i,yindex:yindex+5)=160
    yindex=yindex+6
end
% 创建一个大小为 30*36000 的零矩阵
data = zeros(30, 36000);
% 首行前 6 个数赋值为 200
data(1, 1:6) = 200;
% 对每一行进行循环
for row = 1:30
    % 计算当前行的平移距离
    shift_distance = (row - 1) * 6;
    % 对当前行的数据进行赋值
    for j = 1:180:size(data, 2)
        % 将前一行对应位置的数据平移后赋值给当前行
        data(row, j+shift_distance:j+shift_distance+5) = data(1, j:j+5);
    end
end
% 使用 repmat 函数复制原始矩阵,使其横向复制 200 个副本
replicated_A = repmat(data(:,1:180), 1, 200);
% 使用 cat 函数将复制后的矩阵横向拼接,生成大小为 30*36000 的新矩阵
new_matrix = cat(2, replicated_A);
A1(:,1:36000)=new_matrix

%约束2:出勤率小于0.85
b2=0.85*30*ones(1200,1)
A2 = zeros(1200, 36180);
A2_c=zeros(6,180)
for i=1:6
    A2_c(i,i:6:end)=1
end
% 复制矩阵200次
repeated_matrix = repmat(A2_c, 200, 1);
% 创建一个零矩阵
big_matrix = zeros(1200, 36000);
% 将复制的矩阵放置在对角线上
for i = 1:200
    big_matrix((i-1)*6+1:i*6, (i-1)*180+1:i*180) = repeated_matrix((i-1)*6+1:i*6, :);
end
A2(:,1:36000)=big_matrix

%约束3:连续出勤不超过7天
b3=7*ones(1200,1)
A3=zeros(1200,36180)
A3_c=zeros(6,180)
for i=1:6
    A3_c(i,i:6:49)=1
end
% 复制矩阵200次
repeated_matrix = repmat(A3_c, 200, 1);
% 创建一个零矩阵
big_matrix = zeros(1200, 36000);
% 将复制的矩阵放置在对角线上
for i = 1:200
    big_matrix((i-1)*6+1:i*6, (i-1)*180+1:i*180) = repeated_matrix((i-1)*6+1:i*6, :);
end
A3(:,1:36000)=big_matrix

%约束4:每天出勤一个班次
beq=ones(6000,1)
Aeq=zeros(6000,36180)
for i = 1:6000
    start_col = (i - 1) * 6 + 1;
    end_col = i * 6;
    Aeq(i, start_col:end_col) = 1;
end

%合并约束条件
A=[-A1;A2;A3]
b=[-b1;b2;b3]
%%
clc
clear
close all
load parameter
load data2
xc = ones(200, 30, 6);
yc = ones(30, 6);
% 将矩阵转换为一列
xc1 = reshape(xc, [], 1);
yc1 = reshape(yc, [], 1);
% 定义目标函数系数
f = [xc1;yc1];

% 定义变量类型和上下界
intcon = 1:length(f);
lb = [zeros(length(xc1), 1);zeros(length(yc1), 1)];
ub = [ones(length(xc1), 1);inf*ones(length(yc1), 1)];
% 设置选项以保存迭代信息
options = optimoptions(@intlinprog,'display','iter','OutputFcn',@savemilpsolutions,'PlotFcn',@optimplotmilp);
% 使用CPLEX求解整数规划问题
[x, fval, exitflag, output] = intlinprog(f, intcon, A, b, Aeq, beq, lb, ub, options);

% 输出结果
disp('最优解:');
disp(x);
disp('目标函数值:');
disp(fval);
disp('退出标志:');
disp(exitflag);
%%
center_write=[]
date_write=[]
result_write=[]
banci_write=[]
banci={'00:00-08:00','05:00-13:00','08:00-16:00','12:00-20:00','14:00-22:00 ','16:00-24:00'}
% 重复元胞数组1710次
banci_repeated = (repmat(banci, 1, 30))';
banci_write=banci_repeated
% 指定要保存的Excel文件名
filename = '结果表6.csv';
% 将变量名称写入 Excel 文件的第一列
variable_names = {'分拣中心','日期','班次','出勤员工'}
% 开始日期和结束日期
startDate = datetime(2023, 12, 1);
endDate = datetime(2023, 12, 30);
% 生成时间数据
timeData = startDate:endDate;
% 将日期时间数据转换为指定格式的字符串
timeString = datestr(timeData, 'yyyy/mm/dd');
date=cellstr(timeString)
% 初始化一个空数组来存储扩展后的日期
expanded_date = {};
% 循环遍历每个日期
for i = 1:30
    % 将当前日期重复24次
    repeated_date = cellstr(repmat(date{i}, 6, 1));
    % 将重复后的日期追加到数组中
    expanded_date = [expanded_date; repeated_date];
end
c=num2cell(1:180,1)
date_write=[]
date_write = expanded_date;
center_write=sortedData2{1}(1:180,1)
%%
WWW=[table2cell(center_write), date_write, banci_write]
% 将原始矩阵按每 180 行分组,构成一个大小为 201*180 的矩阵
matrix = reshape(x, 180, 201)';
zs=matrix (1:200,:)
ls=matrix (201,:)
write_maxtrix=[]
for i=1:180
    n=sum(zs(:,i))
    % 使用 repmat 函数将第二行复制 n 次
    new_cell_array = repmat({WWW{i, :}}, n, 1);
    index=find(zs(:,i)==1)
    % 获取矩阵的行数和列数
    [num_rows, num_cols] = size(index);
    % 创建一个空的单元格数组,用于存储转换后的字符串
    string_matrix = cell(num_rows, num_cols);
    % 遍历矩阵的每个元素,将行号转换为字符串形式
    for m = 1:num_rows
        for n = 1:num_cols
            % 将行号转换为字符串,并与 "第" 和 "行" 拼接
            string_matrix{m, n} = ['正式工', num2str(index(m, n))];
        end
    end
    write_maxtrix=[write_maxtrix;new_cell_array string_matrix]
    
    if ls(i)~=0
        % 使用 repmat 函数将第二行复制 n 次
        new_cell_array1 = repmat({WWW{i, :}}, ls(i), 1);
        q1=1:ls(i)
        q1=q1'
        % 获取矩阵的行数和列数
        [num_rows, num_cols] = size(q1);
        % 创建一个空的单元格数组,用于存储转换后的字符串
        string_matrix = cell(num_rows, num_cols);
        % 遍历矩阵的每个元素,将行号转换为字符串形式
        for m = 1:num_rows
            for n = 1:num_cols
                % 将行号转换为字符串,并与 "第" 和 "行" 拼接
                string_matrix{m, n} = ['临时工', num2str(q1(m, n))];
            end
        end
        write_maxtrix=[write_maxtrix;new_cell_array1 string_matrix]
    end
end
%%
xlswrite(filename, [variable_names;write_maxtrix], '结果表6', 'A1');

  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值