MTSP问题——SA退火算法

期末作业; 

import random
import numpy as np
import matplotlib.pyplot as plt

def gen_cities(city_num, random_state=True):
    if random_state:
        cities = (np.random.uniform(0, 2, (city_num, 2)) - 1) * 20000
        np.savetxt('cities.txt', cities)
    else:
        cities = np.loadtxt('cities.txt')
    packages = np.random.randint(1, 10, city_num + 1)
    initial_city = np.random.randint(0, city_num)
    cities[0], cities[initial_city] = cities[initial_city], cities[0]
    cities[0] = (0, 0)
    return cities, packages, initial_city

def plot_map(cities, routes):
    plt.figure(figsize=(10, 10), dpi=100)
    plt.scatter(cities[:, 0], cities[:, 1], s=150)

    colors = ['r', 'g', 'b', 'c', 'm', 'y', 'k']
    for i, route in enumerate(routes):
        color = colors[i % len(colors)]
        for j in range(len(route) - 1):
            plt.plot([cities[int(route[j])][0], cities[int(route[j + 1])][0]],
                     [cities[int(route[j])][1], cities[int(route[j + 1])][1]], c=color)
        plt.plot([cities[int(route[0])][0], cities[int(route[-1])][0]],
                 [cities[int(route[0])][1], cities[int(route[-1])][1]], c=color)

    plt.savefig('cities.png')

def plot_hill(all_best):
    plt.figure(figsize=(5, 5), dpi=500)
    plt.plot(all_best, 'r-',)
    plt.xlabel('Iteration')
    plt.ylabel('Time')
    plt.legend()
    plt.savefig('hills.png')
    plt.show()
    plt.close()

def time_value(deliver_route, packages, package_time, per_distance_time, distances, per_deliver_city):
    value = 0
    value += distances[0][deliver_route[0]] * per_distance_time
    for i in range(per_deliver_city):
        value += packages[deliver_route[i]] * package_time
        if i == per_deliver_city - 1:
            value += distances[deliver_route[i]][0] * per_distance_time
        else:
            value += distances[deliver_route[i]][deliver_route[i + 1]] * per_distance_time
    return value

def time_values(delivers_routes, packages, package_time, per_distance_time, distances, delivers, per_deliver_city):
    delivers_time = [0] * delivers
    for i in range(delivers):
        delivers_time[i] += distances[0][delivers_routes[i][0]] * per_distance_time
        for j in range(per_deliver_city):
            delivers_time[i] += packages[delivers_routes[i][j]] * package_time
            if j < per_deliver_city - 1:
                delivers_time[i] += distances[delivers_routes[i][j]][delivers_routes[i][j + 1]] * per_distance_time
            else:
                delivers_time[i] += distances[delivers_routes[i][j]][0] * per_distance_time
    value = max(delivers_time)
    return delivers_time, value

def get_distance_matrix(cities):
    distances = np.zeros((len(cities), len(cities)))
    for i in range(len(cities)):
        for j in range(len(cities)):
            distances[i][j] = np.sqrt((cities[i][0] - cities[j][0]) ** 2 + (cities[i][1] - cities[j][1]) ** 2)
    return distances

def initial_delivery(city_num, delivers, per_deliver_city):
    city_list = list(range(1, city_num))
    random.shuffle(city_list)
    delivers_routes = np.zeros((delivers, per_deliver_city), dtype=int)
    index = 0
    for i in range(delivers):
        for j in range(per_deliver_city):
            delivers_routes[i][j] = city_list[index]
            index += 1
    return delivers_routes

def SA(city_num, distances, deliver_route, packages, package_time, per_distance_time, per_deliver_city):
    delta = 0.99
    t = 100
    tk = 1
    value_best = float('inf')
    solution_best = deliver_route.copy()

    while t > tk:
        for i in range(1000):
            if np.random.rand() > 0.5:
                loc1, loc2 = random.sample(range(1, city_num), 2)
                deliver_route[loc1], deliver_route[loc2] = deliver_route[loc2], deliver_route[loc1]
            else:
                loc1, loc2, loc3 = sorted(random.sample(range(1, city_num), 3))
                deliver_route[loc1:loc3 + 1] = deliver_route[loc2:loc3 + 1] + deliver_route[loc1:loc2]

            value_new = time_value(deliver_route, packages, package_time, per_distance_time, distances, per_deliver_city)
            if value_new < value_best or np.random.rand() < np.exp(-(value_new - value_best) / t):
                value_best = value_new
                solution_best = deliver_route.copy()

        t *= delta

    return solution_best, value_best

def update(distances, city_num, packages, package_time, per_distance_time, delivers, per_deliver_city):
    delivers_routes = initial_delivery(city_num, delivers, per_deliver_city)
    best_route = delivers_routes.copy()
    history_best = []

    best_delivers_time, best_value = time_values(delivers_routes, packages, package_time, per_distance_time, distances, delivers, per_deliver_city)
    value_current = best_value

    delta = 0.999
    t = 100
    tk = 1

    while t > tk:
        for i in range(1000):
            city_list = []
            for j in range(delivers):
                city_list.extend(delivers_routes[j])

            if np.random.rand() > 0.5:
                loc1, loc2 = random.sample(range(city_num - 1), 2)
                city_list[loc1], city_list[loc2] = city_list[loc2], city_list[loc1]
            else:
                loc1, loc2, loc3 = sorted(random.sample(range(city_num - 1), 3))
                city_list[loc1:loc3 + 1] = city_list[loc2:loc3 + 1] + city_list[loc1:loc2]

            index = 0
            delivers_routes_new = np.zeros_like(delivers_routes)
            for j in range(delivers):
                delivers_routes_new[j] = city_list[index:index + per_deliver_city]
                index += per_deliver_city

            deliver_time_new, value_new = time_values(delivers_routes_new, packages, package_time, per_distance_time, distances, delivers, per_deliver_city)
            if value_new < value_current or np.random.rand() < np.exp(-(value_new - value_current) / t):
                value_current = value_new
                delivers_routes = delivers_routes_new.copy()
                history_best.append(value_new)
                if value_new < best_value:
                    best_value = value_new
                    best_route = delivers_routes_new.copy()
                    best_delivers_time = deliver_time_new.copy()

        t *= delta

    new_best_route = np.zeros((best_route.shape[0], best_route.shape[1] + 1), dtype=int)
    for i in range(len(best_route)):
        new_best_route[i] = np.insert(best_route[i], 0, 0)
    return new_best_route, best_delivers_time, best_value, history_best

def main():
    delivers = 5
    per_deliver_city = 6
    city_num = delivers * per_deliver_city + 1
    cities, packages, initial_city = gen_cities(city_num, random_state=True)
    distances = get_distance_matrix(cities)

    package_time = 10
    per_distance_time = 0.015
    best_route, best_delivers_time, best_value, history_best = update(distances, city_num, packages, package_time, per_distance_time, delivers, per_deliver_city)
    print(best_value, best_delivers_time, "\n", best_route)
    plot_map(cities, best_route)
    plot_hill(history_best)

if __name__ == "__main__":
    main()
    plt.show()

数学建模报告:优化物流配送路线问题

1. 建模问题:

本建模报告针对物流配送问题进行建模,即如何有效地安排配送路线以最小化送货时间和成本。问题涉及在给定城市数量、包裹分布和距离矩阵的情况下,确定最优的配送路线,以最大程度地满足客户需求并降低物流成本。

2. 模型假设:

- 城市之间的距离是通过欧几里得距离来衡量的,即地球上的直线距离。

- 每个城市的包裹数量是已知的,并且在配送过程中不会发生变化。

- 配送员可以在任何时间开始送货,并且可以在需要时调整路线。

- 配送时间是包裹数量和城市间距离的线性函数,且递送过程中没有额外的等待时间或不确定性。

- 模型忽略了交通、天气等因素对配送时间的影响。

3. 符号说明:

N:城市数量

M:配送员数量

C:城市坐标矩阵,C_ij表示第i个城市的坐标

P:每个城市的包裹数量向量,P_i表示第i个城市的包裹数量

D:距离矩阵,D_ij表示第i个城市到第j个城市的距离

T_package:每个包裹的递送时间

T_distance:每单位距离的递送时间

T_total:总递送时间

R:配送路线矩阵,R_ij表示第i个配送员的第j个递送城市

4. 模型建立:

4.1 距离计算:

根据城市坐标矩阵C,计算距离矩阵D,其中D[i][j]表示第i个城市到第j个城市的欧几里得距离。

 4.2 递送时间计算:

对于每个配送路线,根据包裹数量和城市间距离,计算总递送时间T_total。具体计算方法为:

其中,T_distance为每单位距离的递送时间,P_city为当前城市的包裹数量,distance_start为起始城市到第一个递送城市的距离,distance_between cities为递送城市之间的距离。

 4.3 模型优化:

采用模拟退火算法(SA)对配送路线进行优化。在SA算法中,定义目标函数为递送时间T_total,通过迭代过程中的状态转移,寻找能够降低递送时间的更优解。

 5. 模型评价:

- 有效性评价:模拟退火算法具有全局搜索能力,可以在可接受的时间内找到较优解。但实际效果受算法参数和初始状态影响。

- 鲁棒性评价:模型假设简化了现实情况,如忽略了交通、天气等因素,因此在实际应用中可能需要进一步考虑这些因素。

- 可解释性评价:模型的优化过程直观清晰,通过可视化图表可以直观地观察到配送路线的优化情况,便于解释和理解。

- 计算复杂度评价:SA算法的计算复杂度较低,适用于中小规模的物流配送问题,但对于大规模问题可能需要进一步优化算法或采用其他方法。

总体来说,该模型为解决物流配送问题提供了一种有效的优化方案,但在实际应用中需要根据具体情况进行调整和改进。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值