医用口罩共享方案设计与优化:基于图论算法的 Matlab 实现
由于新冠肺炎疫情影响,医用口罩的需求量日益增加。某中学班主任了解到班里 20 名学生的家庭所在小区每周均发放到家庭一定数量的免费医用口罩,于是班主任想到了一个口罩共享方案。通过联系各个家庭,了解到每个学生家庭每周拥有的口罩数量以及最低需求口罩数量,有些家庭是口罩数量不足,而有些家庭是有充足的口罩,如表 1 所示。假设这 20 个家庭每周拥有固定口罩总量及固定需求总量。
1.表 1 显示了班主任和各个学生的家庭地址地理坐标(单位 km)。班主任想针对这个方案到那些口罩充足的学生家里做一次方案说明的家访。考虑到这些家庭地址不同以及节约时间,班主任想一次性完成这些学生的家访。假设班主任采用滴滴打车方式,请为这位班主任设计一个最省钱的家访方案。
2.了解到每个家庭均赞成此口罩共享方案,班主任决定让口罩充足的家庭快递部分口罩给缺乏口罩的家庭。当地针对医用口罩的快递收费标准是 0.5 元/个/ km。假设此方案所支付的快递费全部由学校承担,请为学校设计一套最省钱的口罩共享方案。
3.班主任与各小区物业中心共同商量出了另一套方案。由快递公司设置几个快递点(三到五个),然后由这些快递点向缺乏口罩的家庭配送口罩,而不再由小区来分配口罩,另外口罩充足的家庭无需快递给其他家庭口罩。经协商,快递收费标准提高到 1 元/ km,且不考虑配送口罩的个数。但究竟快递中心点设在哪里,设置多少个仍是个问题。请设计一套节约成本的配送方案,并告知学校此方案是否可行(可以对比第 2 问中的方案)。
表 1
身份 家庭住址 拥有口罩数(个/周) 最低需求口罩数(个/周) 横坐标 x 纵坐标 y 班主任 30 35 学生 1 18 12 14 15 2 23 17 14 9 3 10 0 15 9 4 15 25 4 8 5 13 10 8 10 6 20 20 12 8 7 20 25 13 18 8 32 15 7 11 9 15 18 11 18 10 24 9 23 24 11 3 8 15 4 12 33 3 17 10 13 34 26 5 9 14 37 23 19 27 15 18 4 11 5 16 42 8 20 7 17 50 23 2 6 18 53 16 10 8 19 55 38 11 18 20 7 42 13 18
用正确能运行的matlab代码来写内容:由于题目中需要考虑多个地点之间的距离,因此可以使用图论算法来解决。以下是使用Matlab实现的代码:
第一问:
% 数据
location = [
30, 35; % 班主任
14, 15; 23, 17; 15, 9; 4, 8; 8, 10; 12, 8; 13, 18; 7, 11; 11, 18; 23, 24; ...
15, 4; 20, 7; 5, 9; 19, 27; 11, 5; 20, 7; 2, 6; 10, 8; 13, 18; 11, 18
];
supply = [30; 18; 23; 10; 15; 13; 20; 20; 32; 15; 24; 3; 33; 34; 37; 18; 42; 50; 53; 55];
demand = [35; 12; 17; 0; 25; 10; 25; 15; 18; 9; 3; 3; 26; 23; 4; 8; 23; 16; 38; 42];
% 计算距离矩阵
n = size(location, 1);
dist = zeros(n, n);
for i = 1:n
for j = i+1:n
dist(i,j) = norm(location(i,:)-location(j,:));
dist(j,i) = dist(i,j);
end
end
% 构造图
G = graph(dist);
G.Edges.Weight = ones(numedges(G), 1);
% 求解最小生成树
T = minspantree(G);
% 输出路径
path = dfsearch(T, 1, 'allevents', 'Restart', true);
path = path(find(path.Type == "edge"), :);
disp(path);
第二问:
% 数据
location = [
30, 35; % 班主任
14, 15; 23, 17; 15, 9; 4, 8; 8, 10; 12, 8; 13, 18; 7, 11; 11, 18; 23, 24; ...
15, 4; 20, 7; 5, 9; 19, 27; 11, 5; 20, 7; 2, 6; 10, 8; 13, 18; 11, 18
];
supply = [30; 18; 23; 10; 15; 13; 20; 20; 32; 15; 24; 3; 33; 34; 37; 18; 42; 50; 53; 55];
demand = [35; 12; 17; 0; 25; 10; 25; 15; 18; 9; 3; 3; 26; 23; 4; 8; 23; 16; 38; 42];
% 计算距离矩阵和需求矩阵
n = size(location, 1);
dist = zeros(n, n);
for i = 1:n
for j = i+1:n
dist(i,j) = norm(location(i,:)-location(j,:));
dist(j,i) = dist(i,j);
end
end
demand_matrix = repmat(demand, 1, n);
% 求解运输问题
[cost, supply_matrix, demand_matrix, flow] = transshipment(dist, supply, demand_matrix);
% 输出方案
disp("最小总费用:" + cost + "元");
disp("各家庭配送方案:");
for i = 1:n
for j = 1:n
if flow(i,j) > 0
disp("从家庭" + i + "到家庭" + j + ",配送" + flow(i,j) + "个口罩");
end
end
end
第三问:
% 数据
location = [
30, 35; % 班主任
14, 15; 23, 17; 15, 9; 4, 8; 8, 10; 12, 8; 13, 18; 7, 11; 11, 18; 23, 24; ...
15, 4; 20, 7; 5, 9; 19, 27; 11, 5; 20, 7; 2, 6; 10, 8; 13, 18; 11, 18
];
supply = [30; 18; 23; 10; 15; 13; 20; 20; 32; 15; 24; 3; 33; 34; 37; 18; 42; 50; 53; 55];
demand = [35; 12; 17; 0; 25; 10; 25; 15; 18; 9; 3; 3; 26; 23; 4; 8; 23; 16; 38; 42];
% 计算距离矩阵和需求矩阵
n = size(location, 1);
dist = zeros(n, n);
for i = 1:n
for j = i+1:n
dist(i,j) = norm(location(i,:)-location(j,:));
dist(j,i) = dist(i,j);
end
end
demand_matrix = repmat(demand, 1, n);
% 求解运输问题
[cost, supply_matrix, demand_matrix, flow] = transshipment(dist, supply, demand_matrix);
% 求解最优快递点
n_centers = 3:5;
min_cost = Inf;
min_centers = [];
for k = n_centers
centers = nchoosek(2:n, k-1);
for i = 1:size(centers, 1)
center_dist = zeros(n, k);
for j = 1:k
center_dist(:,j) = dist(:,centers(i,j));
end
center_cost = min(center_dist, [], 2);
[cost, ~, ~] = transshipment(center_dist, supply, demand_matrix, center_cost);
if cost < min_cost
min_cost = cost;
min_centers = centers(i,:);
end
end
end
% 输出方案
disp("最小总费用:" + min_cost + "元");
disp("最优快递点:" + min_centers);
disp("各家庭配送方案:");
for i = 1:n
for j = 1:n
if flow(i,j) > 0
if any(min_centers == i) && any(min_centers == j)
disp("从快递点到家庭" + i + ",配送" + flow(i,j) + "个口罩");
disp("从家庭" + i + "到家庭" + j + ",配送" + flow(i,j) + "个口罩");
disp("从家庭" + j + "到快递点,配送" + flow(i,j) + "个口罩");
else
disp("从家庭" + i + "到家庭" + j + ",配送" + flow(i,j) + "个口罩");
end
end
end
end
需要注意的是,以上代码中使用了一个名为transshipment的自定义函数来求解运输问题。该函数的实现如下:
function [cost, supply_matrix, demand_matrix, flow] = transshipment(cost_matrix, supply, demand_matrix, trans_cost)
% [cost, supply_matrix, demand_matrix, flow] = transshipment(cost_matrix, supply, demand_matrix, trans_cost)
% 求解运输问题(包括转运问题)
% 输入:
% cost_matrix - 距离矩阵或成本矩阵
% supply - 供应量向量
% demand_matrix - 需求矩阵
% trans_cost - 转运成本向量(可选)
% 输出:
% cost - 最小总费用
% supply_matrix - 供应矩阵
% demand_matrix - 需求矩阵
% flow - 流量矩阵
% 初始化供应矩阵、需求矩阵和流量矩阵
n = size(cost_matrix, 1);
supply_matrix = zeros(n, n);
demand_matrix = demand_matrix - supply;
flow = zeros(n, n);
% 如果没有转运成本,则将距离矩阵作为成本矩阵
if nargin < 4
cost_matrix(cost_matrix == 0) = inf;
trans_cost = min(cost_matrix, [], 2);
end
% 求解运输问题
while any(demand_matrix ~= 0)
% 计算可行流量
feasible_flow = min(supply_matrix, repmat(demand_matrix, 1, n));
feasible_flow(feasible_flow < 0) = 0;
% 计算归约成本
reduced_cost = repmat(trans_cost, 1, n) + cost_matrix - repmat(trans_cost', n, 1);
% 求解最小成本流
[u, v, ~] = assignmentoptimal(reduced_cost);
min_cost = sum(reduced_cost(sub2ind([n,n], u, v)));
flow_matrix = zeros(n, n);
for i = 1:length(u)
flow_matrix(u(i),v(i)) = feasible_flow(u(i),v(i)) + 1e-6;
end
% 更新供应矩阵、需求矩阵和流量矩阵
supply_matrix = supply_matrix + flow_matrix;
demand_matrix = demand_matrix - sum(flow_matrix, 1)';
flow = flow + flow_matrix;
end
% 计算总费用
cost = sum(sum(flow .* cost_matrix));
end
原文地址: https://www.cveoy.top/t/topic/oRfF 著作权归作者所有。请勿转载和采集!