基于多目标优化的选址问题:帕累托前沿在资源分配中的应用

#新星杯·14天创作挑战营·第11期#

在城市规划、物流配送、公共服务设施布局等领域,如何在有限的资源下实现最大的效益是一个关键问题。例如,确定多少个供给点(如超市、医院、消防站)既能覆盖尽可能多的需求点(居民区、商业区等),又能控制建设和运营成本。今天,我们通过一段 MATLAB 代码,探索如何利用多目标优化寻找选址问题中的最优解,揭示帕累托前沿在资源分配中的智慧。

一、数据生成:构建虚拟的需求与供给场景 🏙️

n1=100;%需求点个数
Map_max=35;%地图大小
xy1=rand(n1,2)*Map_max;%需求点坐标
n2=100;%供给点个数
xy2=rand(n2,2)*Map_max;%供给点坐标
pop=500+randi(20000,n1,1);%随机生成人口
pop_all=sum(pop);
R=5;%覆盖范围

代码首先设定了需求点(\(n_1 = 100\))和供给点(\(n_2 = 100\))的数量,在大小为 \(\text{Map\_max} = 35\) 的地图上随机生成它们的坐标(\(\text{xy}_1, \text{xy}_2\))。每个需求点的人口数量 \(\text{pop}\) 随机生成(500 到 20000 之间),总人 \(\text{pop\_all}\) 为所有需求点人口之和。覆盖范围 R 设为 5,表示供给点能服务周围 5 单位距离内的需求点。

二、可视化呈现:直观展示站点分布 🌍

figure;%绘图
scatter(xy1(:,1),xy1(:,2),5+pop.^(1/2),pop,'filled')
txt1=1:n1;
text(xy1(:,1)+Map_max/50,xy1(:,2),strcat("需",string(num2str(txt1'))),"FontSize",7);
hold on
scatter(xy2(:,1),xy2(:,2),40,'r^')
text(xy2(:,1)+Map_max/50,xy2(:,2),strcat("供",string(num2str(txt1'))),"FontSize",7);
c1=colorbar;
set(get(c1,'title'),'string','人口');
legend('需求点','供给点');
title('站点位置示意图')

这部分代码绘制了需求点和供给点的分布图。需求点用散点表示,大小与人口数量相关(人口越多点越大),并标注 “需 + 编号”;供给点用红色三角形表示,标注 “供 + 编号”。颜色条显示人口规模,直观呈现了各需求点的重要性。

 

三、距离计算与初始解生成:为优化做准备 🧭

D = pdist2(xy1,xy2);%计算需求点到供给点的距离
G_item=10000;%生成n个解
k=randi(n1,G_item,1);%选取供给点的个数
f2=zeros(G_item,1);
r1cell=cell(G_item,1);
for i=1:G_item%求每个解的覆盖率
    r1 = randperm(n1,k(i));%提取所选供给站
    dtemp=D(:,r1);%提取距离
    bw1=any(dtemp<R,2);%判断哪些需求点被覆盖到
    f2(i)=sum(pop(bw1))/pop_all;%计算覆盖率
    r1cell{i}=r1;
end

D = pdist2(xy1,xy2) 计算每个需求点到所有供给点的距离。然后生成 \(G\_item = 10000\) 个初始解,每个解随机选择 \(k(i)\) 个供给点(\(k(i)\) 随机在 1 到 \(n_1\) 之间)。通过判断需求点到所选供给点的距离是否小于 R,计算每个解的覆盖率 f2(覆盖人口与总人口的比值)。

四、多目标优化:寻找帕累托前沿 🎯

data=[k,-f2];
s=size(data);
options = optimoptions('gamultiobj','PlotFcn',@gaplotpareto,'PopulationSize',s(1),'InitialScores',data,'Generations',1);
[x,fval,exitflag,output,population,scores] = gamultiobj(@(x) x,2,[],[],[],[],[],[],options);

将选点个数 k 和负的覆盖率(因为 gamultiobj 默认最小化,这里要最大化覆盖率,所以取负)组成数据 data。利用 gamultiobj 进行多目标优化,目标是最小化选点个数(k)和最大化覆盖率(\(-f2\))。options 设置绘图函数(绘制帕累托前沿)、种群大小、初始分数和代数。

五、结果展示:帕累托前沿的意义与解读 📈

clf;
plot(fval(:,1),-fval(:,2),'rp','MarkerSize',9)
xlabel('选点个数');ylabel('覆盖率')
title('帕累托前沿')
set(gca,'FontSize',12);
grid on
hold on
plot(data(:,1),-data(:,2),'k.')
legend('帕累托解集','解空间')

绘制帕累托前沿(\(fval(:,1)\) 为选点个数,\(-fval(:,2)\) 为覆盖率),红色圆点表示帕累托解集,黑色点表示所有初始解。帕累托前沿上的点表示在选点个数和覆盖率之间的最优权衡,比如选点个数少则覆盖率低,选点多则覆盖率高,用户可根据实际需求(如成本限制)选择合适的点。 

ind1=zeros(1,size(fval,1));%编号转换
for i=1:size(fval,1)
    ind1(i)=find(all(fval(i,:)==data,2),1);
end
ind1=unique(ind1);
for i=1:size(ind1,2)
    str='--------------------------------';
    disp(str);
    str=['第',num2str(i),'个帕累托解:'];
    disp(str);
    str=['选址个数:',num2str(k(ind1(i)))];
    disp(str);
    str=['选址供给点编号:',num2str(r1cell{ind1(i)})];
    disp(str);
    str=['人口覆盖率:',num2str(f2(ind1(i)))];
    disp(str);
end

最后输出每个帕累托解的详细信息,包括选址个数、供给点编号和覆盖率,方便用户根据具体情况做出决策。

 

六、总结:帕累托前沿的价值与应用拓展 💡

通过这段代码,我们展示了如何利用多目标优化解决选址问题,帕累托前沿为我们提供了一系列最优权衡的选择。在实际应用中,这种方法可用于:

  • 物流配送:确定最佳配送中心数量,平衡建设成本和服务范围。
  • 公共服务:规划医院、学校数量,确保资源高效利用。
  • 通信网络:布置基站数量,优化信号覆盖与建设成本。

帕累托前沿的思想不仅仅适用于选址问题,还可拓展到更多多目标优化场景。它教会我们在资源有限的情况下,如何找到最优的平衡,让每一份投入都发挥最大的价值。下次遇到类似的权衡问题,不妨想想帕累托前沿,让数据为决策指引方向~🌟

完整代码(省流版)

clc;clear;close all;

n1=100;%需求点个数

Map_max=35;%地图大小
xy1=rand(n1,2)*Map_max;%需求点坐标
n2=100;%需求点个数
xy2=rand(n2,2)*Map_max;%供给点坐标

pop=500+randi(20000,n1,1);%随机生成人口
pop_all=sum(pop);
R=5;%覆盖范围
figure;%绘图
scatter(xy1(:,1),xy1(:,2),5+pop.^(1/2),pop,'filled')

txt1=1:n1;
text(xy1(:,1)+Map_max/50,xy1(:,2),strcat("需",string(num2str(txt1'))),"FontSize",7);
hold on
scatter(xy2(:,1),xy2(:,2),40,'r^')
text(xy2(:,1)+Map_max/50,xy2(:,2),strcat("供",string(num2str(txt1'))),"FontSize",7);
c1=colorbar;
set(get(c1,'title'),'string','人口');
legend('需求点','供给点');
title('站点位置示意图')

D = pdist2(xy1,xy2);%计算需求点到供给点的距离

G_item=100000;%生成n个解
k=randi(n1,G_item,1);%选取供给点的个数
f2=zeros(G_item,1);
r1cell=cell(G_item,1);
for i=1:G_item%求每个解的覆盖率
    r1 = randperm(n1,k(i));%提取所选供给站
    dtemp=D(:,r1);%提取距离
    bw1=any(dtemp<R,2);%判断哪些需求点被覆盖到
    f2(i)=sum(pop(bw1))/pop_all;%计算覆盖率
    r1cell{i}=r1;
end

data=[k,-f2];
s=size(data);
% data=-data;
options = optimoptions('gamultiobj','PlotFcn',@gaplotpareto,'PopulationSize',s(1),'InitialScores',data,'Generations',1);
[x,fval,exitflag,output,population,scores] = gamultiobj(@(x) x,2,[],[],[],[],[],[],options);
%fval即为pareto前沿数据

%利用fval数据重新绘制图形灵活度更高
clf;
plot(fval(:,1),-fval(:,2),'rp','MarkerSize',9)
% axis([-1,-0,-1,0])
% set(gca,'XTick',-1:0.1:0,'YTick',-1:0.1:0)
xlabel('选点个数');ylabel('覆盖率')
title('帕累托前沿')
set(gca,'FontSize',12);
grid on

%将pareto前沿与原始数据绘制在同一张图上
hold on
plot(data(:,1),-data(:,2),'k.')
legend('帕累托解集','解空间')
ind1=zeros(1,size(fval,1));%编号转换
for i=1:size(fval,1)
    ind1(i)=find(all(fval(i,:)==data,2),1);
end
ind1=unique(ind1);
for i=1:size(ind1,2)
    str='--------------------------------';
    disp(str);
    str=['第',num2str(i),'个帕累托解:'];
    disp(str);
    str=['选址个数:',num2str(k(ind1(i)))];
    disp(str);
    str=['选址供给点编号:',num2str(r1cell{ind1(i)})];
    disp(str);
    str=['人口覆盖率:',num2str(f2(ind1(i)))];
    disp(str);
end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值