遗传算法解决7和12个客户点的配送问题(仅考虑车辆容量限制,没有行驶距离限制)

4 篇文章 0 订阅
3 篇文章 1 订阅

问题描述

①7个客户点(1-7)和配送中心(0)的序号、坐标及需求量如下
0 18 54 0
1 22 60 0.89
2 58 69 0.14
3 71 71 0.28
4 83 46 0.33
5 91 38 0.21
6 24 42 0.41
7 18 40 0.57
②12个客户点(1-12)和配送中心(0)的序号、坐标及需求量如下
0 81.5 41.5 0
1 87 37 1.2
2 75 53 1.7
3 85 52 1.5
4 89 41 1.4
5 77 58 1.7
6 76 45 1.4
7 87 53 1.2
8 73 38 1.9
9 77 38 1.8
10 73 31 1.6
11 91 47 1.7
12 92 44 1.1

代码

说明:针对小规模的CVRP问题,可以直接进行客户点的随机排列,不需要像31个客户点那样根据距离的远近加入下一个节点。
客户点坐标数据导入:创建文件名为c101的txt文件,将数据复制进去即可,切换不同的案例(从7个客户点到12个客户点)只需要更改文件名即可。
①主函数main

% 问题:找到精确解的概率较低
%编码:自然数编码
%选择:锦标赛和轮盘赌%%轮盘赌的效果完全没有锦标赛的效果好
%交叉:顺序交叉
%变异:两个随机位置互换

clear;
clc;
close all;
tic;
%% 用importdata读取文件并计算各个点之间的距离
CVRP=importdata('c101.txt');
[row,~] = size(CVRP);
dist = zeros(row,row);
for i = 1:row-1
    for j = i+1:row
        dist(i,j) = sqrt(sum((CVRP(i,2:3)-CVRP(j,2:3)).^2));
    end
end
dist = dist + dist';
row = row - 1;%客户点的数量

% 参数设置
[N,D,volume,Iter,Pc,Pm] = constant(row);
GA = zeros(N,D+1);%GA数组位置申请
Path = inf(N,2*D+2);%定义路径的数组,前2*D存放具体路径,2*D+1、2*D+2分别为车辆书及路径长度

% 初始化
[GA,Path] = initialization(CVRP,dist,N,D,volume,GA,Path);

%% 迭代
[GA,Path,Gbest] = iteration(N,D,volume,Iter,Pc,Pm,CVRP,dist,GA,Path);

%% 命令行显示
[value,row] = min(Path(:,2*D+2));
[~,col] = find(Path(row,1:2*D)==0);
[~,k] = size(col);
for i = 1:k-1
    disp(['车辆',num2str(i),':',num2str(Path(row,col(i):col(i+1)))]);
end
disp(['最短总路程:',num2str(Path(row,2*D+2))]);        %输入多个参数进行显示,除了用num2str显示数值,还需要将所有输入加上方括号!!

plot(Gbest);
draw(CVRP);
hold on;
grid on ;
for i = 1:k-1
    c = Path(row,col(i):col(i+1)) + 1;
    plot(CVRP(c,2),CVRP(c,3));
end
toc;

②参数函数constant

function [N,D,volume,Iter,Pc,Pm] = constant(row)

N = 100;
D = row;
if D ==7
    volume = 1;
elseif D ==12
    volume = 6;
end
Iter = 200;

Pc = 0.8;
Pm = 0.1;

③初始化函数initialization

function [GA,Path] = initialization(CVRP,dist,N,D,volume,GA,Path)

for i = 1:N
    GA(i,1:D) = randperm(D);%将客户点随机排列   
    Path(i,:) = pathdecode(CVRP,D,volume,GA(i,1:D));
    GA(i,D+1) = fitness(Path(i,:),D,dist);%计算距离  
    Path(i,2*D+2) = GA(i,D+1);
end

④编码函数pathdecode

function path = pathdecode(CVRP,D,volume,x)
%解码
path = inf(1,2*D+2);%存放解码后的路径
k = 1;%路径中已有的节点个数
path(k) = 0;%第一个节点是配送中心
heavy = 0;%初始的车辆载重为0
numcar = 0;%车辆数初始为0
for j = 1:D
    k = k + 1;%已有的节点个数加1
    if heavy+CVRP(x(j)+1,4)<volume
        path(k) = x(j);
        heavy = heavy + CVRP(x(j)+1,4);%累计车辆的载重
    else
        heavy = CVRP(x(j)+1,4);%重置车辆的载货量
        path(k) = 0;%添加一个配送中心节点序号
        k = k + 1;
        path(k) = x(j);%下一个加入路径的节点
        numcar = numcar + 1;%车辆数加1
    end
end
k = k + 1;
numcar = numcar + 1;
path(k) = 0;%车辆回到配送中心
path(2*D+1) = numcar;%记录车辆数

⑤适应度函数fitness

function y = fitness(path,D,dist)

y = 0;%计算路径长度
pathlong = path(2*D+1)+1+D;
for i = 1:pathlong-1
    y = y + dist(path(i)+1,path(i+1)+1);
    %位置 1 处的索引无效。数组索引必须为正整数或逻辑值。原因是函数调用的参数输入问题或者确实是本行有问题!!!!
end

⑥迭代函数iteration

function [GA,Path,Gbest] = iteration(N,D,volume,Iter,Pc,Pm,CVRP,dist,GA,Path)
Gbest = zeros(1,Iter);%存放每次迭代的最佳距离值
for iter = 1:Iter
    Parent1 = select(N,D,GA);
    Parent2 = select(N,D,GA);%分别通过锦标赛选择两个父代群
    
    GA = crossover(N,D,Pc,GA,Parent1,Parent2);%交叉操作
    
    GA = mutation(N,D,Pm,GA);%变异操作
    for i = 1:N
        Path(i,:) = pathdecode(CVRP,D,volume,GA(i,1:D));
        GA(i,D+1) = fitness(Path(i,:),D,dist);
        Path(i,2*D+2) = GA(i,D+1);
    end
    Gbest(1,iter) = min(GA(:,D+1));
end

⑦选择函数select

function  x = select(N,D,GA)
%锦标赛
x = GA;
 for i = 1:N
     candi = randperm(N,5);%在所有染色体中随机选取5个个体
     [fit,row] = min(GA(candi,D+1));%找路径最短的个体
     if fit<x(i,D+1)
         x(i,:) = GA(candi(row),:);%如果5个中最小的染色体产生的距离小于原数组中的染色体距离,则存放在父代的染色体群体中
     end
 end

⑧交叉函数crossover

function x = crossover(N,D,Pc,GA,Parent1,Parent2)
%顺序交叉
x = GA;
for i = 1:N
    parent1 = Parent1(i,:);
    parent2 = Parent2(i,:);%分别选择两个父代群中的第i个染色体进行交叉
    if rand>Pc
        x(i,:) = parent1;
        if parent1(D+1)>parent2(D+1)
            x(i,:) = parent2;%当随机数大于交叉概率,选择两个父代中距离最短的那个继承下来;
        end
    else%当随机数小于交叉概率时,进行交叉操作
        point = randperm(D,2);
        point1 = min(point);
        point2 = max(point);%指定大小交叉点
        while max(point)-min(point)>=5
            %交叉点之间的距离≥5则交叉不会产生变化
            point = randperm(D,2);%随机选择1-D范围内的两个不同的整数
            point1 = min(point);
            point2 = max(point);%指定大小交叉点
        end
        x(i,point1:point2) = parent1(point1:point2);%子代交叉点之间是父代1交叉点之间的序号
        parent2_1 = [parent2(point2+1:D) parent2(1:point2)];%父代2从交叉点2后一位开始循环一轮到该交叉点
        for cross = point1:point2
            parent2_1(parent2_1==x(i,cross)) = [];%将parent2_1中与子代中重复的序号去除
        end
        if point1 == 1
            x(i,point2+1:D) = parent2_1;%如果交叉点1是第二位,那直接赋值
        elseif point2 ==D
            x(i,1:point1-1) = parent2_1;%如果交叉点2是最后一位,也可以直接赋值
        else
            x(i,1:point1-1) = parent2_1(1:point1-1);%交叉点前的一段序号赋值
            x(i,point2+1:D) = parent2_1(point1:end);%交叉点后的一段序号赋值
        end
    end
end

⑨变异函数mutation

function x = mutation(N,D,Pm,GA)
%变异
x = GA;
for i = 1:N
    if rand <= Pm%随机数小于变异概率则进行变异操作
        point1 = 0;
        point2 = 0;
        while point1 == point2%避免两个变异点相同
           point = randi([1,D],1,2);%产生2-D之间的两个不同的随机整数
           point1 = min(point);
           point2 = max(point);%两个变异点根据大小赋值
        end
        temp = x(i,point1);
        x(i,point1) = x(i,point2);
        x(i,point2) = temp;%两个变异点互换位置
    end   
end

⑩绘图draw

function draw(CVRP)

figure(5);
% axis([0 110 0 110]);
title('配送路线');
hold on ;
grid on ;
plot(CVRP(:,2),CVRP(:,3),'r.','linewidth',10);%不用循环,
end

结果

①7个客户点
路线图
命令行结果
最短路径迭代变化
②12个客户点
路线图
命令行结果
最短路径迭代变化

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值