【纠错】遗传算法求解VRP计算车辆容量限制的代码有bug

关联文章

关联的博客文章为:《遗传算法求解带时间窗的VRP问题(python)

原出错函数

源程序代码如下:

python 复制代码
def vehicle_capacity_restraint(chrom):
    # 计算一条染色体的车辆容量限制
    individual = copy.deepcopy(chrom)
    split_flag_node = True
    total_path_list = []
    while split_flag_node:
        vehicle_load_list = demand_quantity[0, individual]
        cumsum_list = np.cumsum(vehicle_load_list)
        if len(np.where(cumsum_list > vehicle_capacity_max)[0]) != 0: # 累加值大于车辆容量的位置
            split_flag_node = np.where(cumsum_list > vehicle_capacity_max)[0][0]
        else:
            # 生成的染色体刚好够一辆车运输
            split_flag_node = False
            path_list = [0] * (len(individual) + 2)  # 前后两个配送中心节点
            path_list[1:-1] = copy.deepcopy(individual)
            total_path_list.append(path_list)
        if split_flag_node:
            path_list = [0] * (split_flag_node + 2)  # 前后两个配送中心节点
            path_list[1:-1] = copy.deepcopy(individual[:split_flag_node])
            total_path_list.append(path_list)
            individual = individual[split_flag_node:]
    return total_path_list

运行其他的算例发现如下错误:

python 复制代码
total_path_list [[0, 1, 2, 0], [0, 4, 0], [0, 8, 5, 0], [0, 6, 0], [0, 7, 0]]
total_path_list [[0, 5, 0]]
population [[ 1  2  4  8  5  6  7  3  9 10]
 [ 5 10  3  7  6  9  4  1  2  8]]
total_path_list [[0, 1, 2, 0], [0, 4, 0], [0, 8, 5, 0], [0, 6, 0], [0, 7, 0]]
routes [1, 2, 4, 8, 5, 6, 7]

分析错误表象为:使用函数vehicle_capacity_restraint()不能很好的根据车辆的最大容量限制切割染色体,根据容量限制插入配送中心节点0。

如下为算例10个需求服务点的需求配送量:

车辆的最大载重量vehicle_capacity_max = 3。

在某些场景下该函数切出来的车辆路径是正确的,需要车辆的载重量扩大点

vehicle_capacity_max = 5的场景下计算是可行的,如下:

python 复制代码
total_path_list [[0, 10, 0], [0, 4, 1, 2, 0], [0, 9, 3, 0], [0, 8, 5, 0], [0, 6, 7, 0]]
total_path_list [[0, 8, 5, 0], [0, 10, 0], [0, 7, 6, 0], [0, 2, 3, 0], [0, 1, 4, 9, 0]]
population [[10  4  1  2  9  3  8  5  6  7]
 [ 8  5 10  7  6  2  3  1  4  9]]
total_path_list [[0, 10, 0], [0, 4, 1, 2, 0], [0, 9, 3, 0], [0, 8, 5, 0], [0, 6, 7, 0]]
routes [10, 4, 1, 2, 9, 3, 8, 5, 6, 7]

当vehicle_capacity_max = 3的场景,函数vehicle_capacity_restraint()计算会出现错误,不能正确的根据车辆容量限制切割配送路线,如下:

python 复制代码
chrom [ 8  2  7  5  4 10  9  6  1  3]
split_flag_node 2
split_flag_node 2
split_flag_node 1
total_path_list [[0, 8, 2, 0], [0, 7, 5, 0], [0, 4, 0]]

代码捉虫

修改代码如下:

python 复制代码
def vehicle_capacity_restraint(chrom):
    print("chrom", chrom)
    # 计算一条染色体的车辆容量限制
    individual = copy.deepcopy(chrom)
    split_node_flag = True
    split_node_index = -1
    total_path_list = []
    while split_node_flag:
        vehicle_load_list = demand_quantity[0, individual]
        cumsum_list = np.cumsum(vehicle_load_list)
        print("cumsum_list", cumsum_list)
        if len(np.where(cumsum_list > vehicle_capacity_max)[0]) != 0:  # 累加值大于车辆容量的位置
            print("111", np.where(cumsum_list > vehicle_capacity_max)[0])
            split_node_index = np.where(cumsum_list > vehicle_capacity_max)[0][0]
        else:
            if len(cumsum_list) == 0:
                split_node_flag = False
                continue
            else:
                if split_node_index == -1:
                    print("222")
                    split_node_flag = False
                    # 生成的染色体刚好够一辆车运输
                    path_list = [0] * (len(individual) + 2)  # 前后两个配送中心节点
                    path_list[1:-1] = copy.deepcopy(individual)
                    total_path_list.append(path_list)
        if (split_node_index) != 0 and (split_node_index != -1):
            print("split_node_index", split_node_index)
            path_list = [0] * (split_node_index + 2)  # 前后两个配送中心节点
            path_list[1:-1] = copy.deepcopy(individual[:split_node_index])
            total_path_list.append(path_list)
            individual = individual[split_node_index:]
        elif len(cumsum_list) == 0:
            split_node_flag = False
            continue
        elif split_node_index != -1:
            print("333", split_node_index)
            path_list = [0] * (1 + 2)  # 前后两个配送中心节点
            path_list[1] = copy.deepcopy(individual[0])
            total_path_list.append(path_list)
            individual = individual[1:]
        else:
            pass
    print("total_path_list", total_path_list)
    return total_path_list

满足第一种场景,vehicle_capacity_max = 22 # 车辆的最大载重量,即刚好使用一辆车可以装满所有10个需求节点的货物,运输路线只有一条,即total_path_list [[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 0]]:

python 复制代码
chrom [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
cumsum_list [ 1.   4.5  6.5  7.5 10.5 12.5 14.5 16.  20.  21.5]
222
total_path_list [[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 0]]

Process finished with exit code 0

满足第二种场景,vehicle_capacity_max = 1 # 车辆的最大载重量,车辆的运输能力极小时,函数vehicle_capacity_restraint()也能正确的工作,得到极大值,也就是派10辆车完成运输任务,如下结果total_path_list [[0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0], [0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 1, 0]]

python 复制代码
chrom [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
cumsum_list [ 1.   4.5  6.5  7.5 10.5 12.5 14.5 16.  20.  21.5]
111 [1 2 3 4 5 6 7 8 9]
split_node_index 1
cumsum_list [ 3.5  5.5  6.5  9.5 11.5 13.5 15.  19.  20.5]
111 [0 1 2 3 4 5 6 7 8]
333 0
cumsum_list [ 2.   3.   6.   8.  10.  11.5 15.5 17. ]
111 [0 1 2 3 4 5 6 7]
333 0
cumsum_list [ 1.   4.   6.   8.   9.5 13.5 15. ]
111 [1 2 3 4 5 6]
split_node_index 1
cumsum_list [ 3.   5.   7.   8.5 12.5 14. ]
111 [0 1 2 3 4 5]
333 0
cumsum_list [ 2.   4.   5.5  9.5 11. ]
111 [0 1 2 3 4]
333 0
cumsum_list [2.  3.5 7.5 9. ]
111 [0 1 2 3]
333 0
cumsum_list [1.5 5.5 7. ]
111 [0 1 2]
333 0
cumsum_list [4.  5.5]
111 [0 1]
333 0
cumsum_list [1.5]
111 [0]
333 0
cumsum_list []
total_path_list [[0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0], [0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 1, 0]]

Process finished with exit code 0

满足第三种场景,vehicle_capacity_max = 5 # 车辆的最大载重量,也就是没有修改函数前,函数能实现的计算功能。

python 复制代码
chrom [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
cumsum_list [ 1.   4.5  6.5  7.5 10.5 12.5 14.5 16.  20.  21.5]
111 [2 3 4 5 6 7 8 9]
split_node_index 2
cumsum_list [ 2.   3.   6.   8.  10.  11.5 15.5 17. ]
111 [2 3 4 5 6 7]
split_node_index 2
cumsum_list [ 3.   5.   7.   8.5 12.5 14. ]
111 [2 3 4 5]
split_node_index 2
cumsum_list [2.  3.5 7.5 9. ]
111 [2 3]
split_node_index 2
cumsum_list [4.  5.5]
111 [1]
split_node_index 1
cumsum_list [1.5]
split_node_index 1
cumsum_list []
total_path_list [[0, 2, 3, 0], [0, 4, 5, 0], [0, 6, 7, 0], [0, 8, 9, 0], [0, 10, 0], [0, 1, 0]]

Process finished with exit code 0

满足第四种场景,vehicle_capacity_max = 100 # 车辆的最大载重量,当车辆最大载重量即运输能力极大时,函数也能够很好的计算配送路线,total_path_list [[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 0]]

python 复制代码
chrom [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
cumsum_list [ 1.   4.5  6.5  7.5 10.5 12.5 14.5 16.  20.  21.5]
222
total_path_list [[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 0]]

Process finished with exit code 0

运用实例

vehicle_capacity_max = 5 # 车辆的最大载重量

目标函数如下:

python 复制代码
# 目标函数:使用车辆数量最少+车辆的总行驶距离最小。
# 约束条件:车辆载重量限制+硬时间窗限制
# 由于出动一辆车的固定成本远远大于车辆的行驶成本,
# 所以,本文将车辆数最小作为最小总成本的主要目标 ,而将路程最小作为次要目标 。

def main_target_func(chrom):
    # 使用车辆数量最少
    vehice_num = 0
    routes = get_feasible_route(chrom)
    print("routes", routes)
    for path in routes:
        for node in path[1:-1]:
            if node == 0:
                vehice_num += 1
    return vehice_num


def minor_target_func(chrom):
    # 车辆的总行驶距离最小
    # 适应度函数是总路线长度最小
    routes = get_feasible_route(chrom)
    total_length = 0
    for route in routes:
        total_length += get_route_length(route)
    target_value = total_length
    return target_value


def calculate_fitness(chrom):
    target_value = 0.6*main_target_func(chrom) + 0.4*minor_target_func(chrom)
    return target_value

遗传算法计算得到如下的结果即算法迭代图形:

相关推荐
xiaoshiguang34 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
别NULL4 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇4 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
yuanbenshidiaos6 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习6 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA6 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo6 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc6 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
游是水里的游7 小时前
【算法day20】回溯:子集与全排列问题
算法