目录
(3)如果考虑有优先客户(某个客户指定某个时间之前必须送到的优先 策略)最优路径如何变化?
(4)平衡策略,总送餐时间和总等待时间达到平衡,最优路径如何?
作业名称:外卖送餐路径优化算法
•
作业描述:地图数据,至少200个节点,有餐馆(出发地)、小区(目的地)、路口( 十字、丁字、五字)等节点,单向道、双向道都有,绘制网络图,形成邻接矩阵数据 。可以使用带权重的邻接矩阵随机生成,直接代替地图数据。假设1个外卖小哥从某个 餐馆至少送10份订餐(不同小区节点)。
• 已知条件:假设送餐小哥车速v,每个订餐客户i要求的等待时间是t(i),每个客户节点i
的距离是s(i)(自己可以给出合理的具体数值)
• 要求:设计不同策略下的最优路径算法并实现:
•
(1)计算最优路径(总送餐时间最短策略)。
•
(2)如果目标是客户总最短等待时间策略,最优路径如何?
•
(3)如果考虑有优先客户(某个客户指定某个时间之前必须送到的优先
策略)最优路径如何变化?
•
(4)平衡策略,总送餐时间和总等待时间达到平衡,最优路径如何?
•
(5)可视化展示每一种最优路线图
•
说明:展示时,每个小组人员都上来讲,按照分工讲。
•
更高的要求(可选做):开发一个app,在网络上,输入餐馆节点位置,
输入10个以上订餐节点位置,再选择最优策略,系统可以自动给出推荐
的最优路线(注意,这个内容是选作,不作为本次作业的要求,仅提供大家思考的方向)
(1)计算最优路径(总送餐时间最短策略)
运算结果如下
(输入窗口)
%主程序main
clc,clear,close all;
%先生成一个随机的矩阵map储存200个点间的相互距离
tf=eye(200,200);
for i=1:200
map(i,i)=0;
end
for i=1:200
for j=(i+1):200
tf(i,j)=1;
end
for j=1:(i-1)
tf(i,j)=randi([0,1],1,1);
if tf(i,j)==1
map(i,j)=map(j,i);
else
map(i,j)=10000;
end
end
end
for i=1:200
for j=1:200
map(i,j)=map(j,i);
end
end
map1=map;
%dist用来存储两个点之间的距离
for i=1:200
for j=i:200
dist(i,j)=map(i,j);
dist(j,i)=dist(i,j);
end
end
real_world=10000*randi([0,1],200);
for point=1:200
real_world(point,point)=0;
end
%随机定义不连通道路
dist=dist+real_world;
route=cell(200,200);%用元胞数组记录相应两点间的最短路径
%计算最优距离与最优路线矩阵:dist_good对应两点间最小值,route对应两点间最短路径
[dist_good,route]=floyd(dist,route);
%(1)没有优先顺序时
num=input('请输入订单数:')+1;
VIP=[1 (input('请输入VIP订单(数组形式,若无则输入 0):'))+1];
dist_main=dist_good(1:num,1:num); % 抽取 num+1 个节点,将每个订单理解为一个地点
all_route=1;% 起始点为 1
%用贪心算法计算最优路线与总距离
[sum,all_route]=route_search(dist_main,route,all_route,VIP);
%弗洛伊德算法计算出两点之间的最短路线,记录进矩阵
%弗洛伊德算法的目的:得到最优相邻矩阵和最优路径矩阵
%输入当前的相邻矩阵和记忆最短路径的route矩阵
function[dist,route]=floyd(dist,route)
%i代表中转点
%三层嵌套循环
for i=1:200
for j=1:200
for k=1:200
if dist(j,k)>dist(j,i)+dist(i,k)
dist(j,k)=dist(j,i)+dist(i,k);
route{j,k}=[route{j,i} i route{i,k}];
end
end
end
end
end
%贪心算法寻找最优路线
function[sum,all_route]=route_search(dist_main,route,all_route,VIP)
%首先利用贪心算法在 num 个节点中找出最优通路,存入 all_route之中,然后返回最短路径
num=size(dist_main,1);
record=linspace(1,num,num); %计算快递小哥到过的地点
record(1)=0;%除去快递小哥的出发地——餐馆
sum=0;%表示快递小哥跑的总距离
%对于VIP客户进行优先处理
size_VIP=size(VIP,2);
for i=1:size_VIP
next=VIP(i);
if next==0
break %条件判断,所有VIP客户均送完后终止循环
elseif next==1
continue
end
former=VIP(i-1);
record(next)=0;
all_route=[all_route route{former,next} next];%存入路径
sum=sum+dist_main(former,next);%把送VIP客户的路程长度相加
end
%用贪心算法处理其他的地点
former=next;
while any(record)
main=100;%此处表示近似无穷大
for i=1:num
if(ismember(i,record))&&(main>dist_main(former,i))
next=i;
main=dist_main(former,next);
end
end
all_route=[all_route route{former,next} next];
former=next;
sum=sum+main;%再加上给普通客户送餐的路程长度
record(next)=0;
index = 1:size(map1,1);
names = {};
for ii = index
names{ii} = num2str(index(ii));
end
%% 定义图像G
G = graph(map1,names);
%% 指定每个点的坐标
x = randperm(10);
y = randperm(20,10);
figure
p = plot(G,'go-','LineWidth',0.000001,'MarkerSize',10);
highlight(p,all_route, 'EdgeColor', 'r')
highlight(p,all_route,'NodeColor','r')
end
end
(2)如果目标是客户总最短等待时间策略,最优路径如何
输入
输出
点与点之间是有连线的
%代码如下
A=randi(100,200,200);
route=cell(200,200);%存储各点之间的最短路径
for i=1:200
A(i,i)=0;
end
for i=1:200
for j=(i+1):200
tf(i,j)=1;
end
for j=1:(i-1)
tf(i,j)=randi([0,1],1,1);
if tf(i,j)==1
A(i,j)=A(j,i);
else
A(i,j)=10000;
end
end
end
for i=1:200
for j=1:200
A(i,j)=A(j,i);
end
end
fprintf("速度默认值为5m/s")
target=input("请输入所有客户的位置数组:");%target:目标客户的位置
st=input("请输入起点");
%% 随机数生成tf邻接矩阵,map距离矩阵
tf=eye(200,200);
map=randi(100,200,200);
route=cell(200,200);%存储各点之间的最短路径
v=5;%速度
for i=1:200
map(i,i)=0;
end
for i=1:200
for j=(i+1):200
tf(i,j)=1;
end
for j=1:(i-1)
tf(i,j)=randi([0,1],1,1);
if tf(i,j)==1
map(i,j)=map(j,i);
else
map(i,j)=10000;
end
end
end
%% 弗洛伊德算法求任意两点之间的最短路径
for i=1:200
for j=1:200
for k=1:200
if map(j,k)>map(j,i)+map(i,k)
map(j,k)=map(j,i)+map(i,k);
route{j,k}=[route{j,i} i route{i,k}];
end
end
end
end
%% 贪心求解
all_dist=0;%总距离
all_route=st;%总路线
all_time=0;%总等待时间
num=numel(target);%顾客数量
judge=ones(1,num);%标记节点
flag=1;
former=st;
while (flag<=num)
min_dist=1000;
min_target=1;
for i=1:num%贪心寻找距离former最短的点
if min_dist>map(former,target(i)) &&judge(i)==1
min_dist=map(former,target(i));
min_target=i;
end
end
judge(min_target)=0;
all_route=[all_route route{former,target(min_target)} target(min_target)];
all_dist=all_dist+min_dist;
all_time=all_time+(num+1-flag)*(min_dist/v);
former=target(min_target);
flag=flag+1;
end
%% 输出结果
fprintf("最优路径是:")
fprintf("%5d",all_route)
fprintf("\n最短距离是:")
fprintf("%d",all_dist)
fprintf("\n顾客总最短等待时间是:")
fprintf("%d",all_time)
index = 1:size(A,1);
names = {};
for ii = index
names{ii} = num2str(index(ii));
end
% 定义图像G
G = graph(A,names);
%% 指定每个点的坐标
x = randperm(10);
y = randperm(20,10);
%绘制无向图
figure
p = plot(G,'go-','LineWidth',0.000001,'MarkerSize',10);
%把最优路径和要经过的节点高亮出来
highlight(p,all_route, 'EdgeColor', 'r')
highlight(p,all_route,'NodeColor','r')
(3)如果考虑有优先客户(某个客户指定某个时间之前必须送到的优先 策略)最优路径如何变化?
输入
输出
%代码如下
st=input("请输入起点");
VIP=input("请输入vip的位置");
target=input("请输入普通客户的位置数组:");%target:目标客户的位置
str=VIP;
%% 随机数生成tf邻接矩阵,map距离矩阵
tf=eye(200,200);
map=randi(100,200,200);
route=cell(200,200);%存储各点之间的最短路径
for i=1:200
map(i,i)=0;
end
for i=1:200
for j=(i+1):200
tf(i,j)=1;
end
for j=1:(i-1)
tf(i,j)=randi([0,1],1,1);
if tf(i,j)==1
map(i,j)=map(j,i);
else
map(i,j)=10000;
end
end
end
for i=1:200
for j=1:200
map(i,j)=map(j,i);
end
end
%% 计算VIP路线
[vip_distance,vip_route]=vip(map,st,VIP);
%% 弗洛伊德算法求任意两点之间的最短路径
for i=1:200
for j=1:200
for k=1:200
if map(j,k)>map(j,i)+map(i,k)
map(j,k)=map(j,i)+map(i,k);
route{j,k}=[route{j,i} i route{i,k}];
end
end
end
end
%% 贪心求解
all_dist=0;%总距离
all_route=str;%总路线
all_time=0;%总等待时间
num=numel(target);%顾客数量
judge=ones(1,num);%标记节点
flag=1;
former=str;
while (flag<=num)
min_dist=1000;
min_target=1;
for i=1:num%贪心寻找距离former最短的点
if min_dist>map(former,target(i)) &&judge(i)==1
min_dist=map(former,target(i));
min_target=i;
end
end
judge(min_target)=0;
all_route=[all_route route{former,target(min_target)} target(min_target)];
all_dist=all_dist+min_dist;
former=target(min_target);
flag=flag+1;
index = 1:size(map,1);
names = {};
for ii = index
names{ii} = num2str(index(ii));
end
% 定义图像G
G = graph(map,names);
%% 指定每个点的坐标
x = randperm(10);
y = randperm(20,10);
figure
p = plot(G,'go-','LineWidth',0.000001,'MarkerSize',10);
highlight(p,all_route, 'EdgeColor', 'r')
highlight(p,all_route,'NodeColor','r')
end
%% 输出结果
fprintf("\nvip客户最短距离是:")
fprintf("%d",vip_distance)
fprintf("\nvip客户最短路径是:")
fprintf("%5d ",vip_route)
fprintf("\n普通客户最优路径是:")
fprintf("%5d",all_route)
fprintf("\n普通客户最短距离是:")
fprintf("%d",all_dist)
同时第三题我们还定义了一个叫vip的函数
%代码如下
function [distance,path] = vip( W,st,e )
%vip函数中w为距离矩阵,st为起点,e为终点
n=length(W);
D = W(st,:);
visit= ones(1,n); visit(st)=0;
parent = zeros(1,n);
path =[];
for i=1:n-1
temp = [];
for j=1:n
if visit(j)
temp =[temp D(j)];
else
temp =[temp inf];
end
end
[value,index] = min(temp);
visit(index) = 0;
for k=1:n
if D(k)>D(index)+W(index,k)
D(k) = D(index)+W(index,k);
parent(k) = index;
end
end
end
distance = D(e);
t = e;
while t~=st && t>0
path =[t,path];
p=parent(t);t=p;
end
path =[st,path];
End
(4)平衡策略,总送餐时间和总等待时间达到平衡,最优路径如何?
注:这个计算过程采用了遍历的方法,运行时间很长,但是很有逻辑
%主代码如下
tf=eye(200,200);
map=randi(50,200,200);
pre=zeros(200,200);
for i=1:200
map(i,i)=0;
end
for i=1:200
for j=(i+1):200
tf(i,j)=1;
end
for j=1:(i-1)
tf(i,j)=randi([0,1],1,1);
if tf(i,j)==1
map(i,j)=map(j,i);
else
map(i,j)=10000;
end
end
end
for i=1:200
for j=1:200
map(i,j)=map(j,i);
end
end
dis=zeros(200,200);
for i=1:200
for j=1:200
dis(i,j)=map(i,j);
end
end
for i=1:200
for j=1:200
pre(i,j)=i;
end
end
for k=1:200
for i=1:200
for j=1:200
if dis(i,k)+dis(k,j)<dis(i,j)
dis(i,j)=dis(i,k)+dis(k,j);
pre(i,j)=k;
end
end
end
end
global mid pos perm visit dis min road min_diliver min_wait;
min=10000;
min_diliver=10000;
min_wait=10000;
visit=zeros(1,10);
perm=zeros(1,10);
road=[];
pos=randperm(200);
pos=pos(1:11);
dfs(1,10);
road=[pos(1) road];
for i=1:10
mid=road(i+1);
while mid~=road(i)
mid=pre(road(i),mid);
if mid==road(i)
break;
end
road=[road(1:i),mid,road(i+1:end)];
end
end
index = 1:size(map,1);
names = {};
for ii = index
names{ii} = num2str(index(ii));
end
% 定义图像G
G = graph(map,names);
%% 指定每个点的坐标
x = randperm(10);
y = randperm(20,10);
figure
p = plot(G,'go-','LineWidth',0.000001,'MarkerSize',10);
highlight(p,road, 'EdgeColor', 'r')
highlight(p,road,'NodeColor','r')
fprintf("最短送餐时间是:")
fprintf("%d",min_diliver)
fprintf("最短等待时间是:")
fprintf("%d",min_wait)
%定义的函数
function f=dfs(step,n)
global mid pos perm visit dis min road min_diliver min_wait;
if step==n+1
temp=(n-1)*dis(pos(1),perm(1));
temp_diliver=dis(pos(1),perm(1));
temp_wait=temp+temp_diliver;
for j=1:n-1
temp=temp+(n-j-1)*dis(perm(j),perm(j+1));
temp_diliver=temp_diliver+dis(perm(j),perm(j+1));
temp_wait=temp_wait+(n-j)*dis(perm(j),perm(j+1));
end
if temp<min
min=temp;
min_diliver=temp_diliver;
min_wait=temp_wait;
road=perm;
end
else
for i=1:n
if visit(i)==0
visit(i)=1;
perm(step)=pos(i+1);
dfs(step+1,n);
visit(i)=0;
end
end
end