期末作业;
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算法的计算复杂度较低,适用于中小规模的物流配送问题,但对于大规模问题可能需要进一步优化算法或采用其他方法。
总体来说,该模型为解决物流配送问题提供了一种有效的优化方案,但在实际应用中需要根据具体情况进行调整和改进。