赞
踩
VRP(Vehicle Routing Problem)问题和TSP(Traveling Salesman Problem)问题都是优化问题,但它们在问题设置和目标函数上存在一些区别。
TSP问题是经典的组合优化问题,其目标是找到一条最短路径,使得一名推销员从一个城市出发,经过所有其他城市后回到起点城市,同时每个城市只能访问一次。TSP问题的目标是最小化总的旅行距离或旅行时间。
VRP问题是在TSP问题的基础上进行扩展的一类问题。VRP问题考虑的是在给定一组客户需求和一组配送车辆的情况下,如何安排车辆的路径,以便满足所有客户的需求,并且使得总的配送成本最小化。VRP问题通常包括以下要素:
在VRP问题中,目标是找到一组车辆的路径,使得满足客户需求的同时,总的配送成本最小化。这个成本可以是行驶距离、行驶时间、车辆数量等。
因此,可以说VRP问题是TSP问题的一种扩展形式,考虑了更多实际配送问题的约束和要素。在VRP问题中,需要解决的是如何合理分配车辆、安排路径以及满足客户需求的问题,而不仅仅是寻找最短路径。
VRPTW(Vehicle Routing Problem with Time Windows)
在VRPTW中,有一组客户需要被服务,这些客户位于不同的位置,每个客户有特定的需求量和时间窗口。时间窗口定义了每个客户允许被访问的时间范围,即服务必须在时间窗口内完成。此外,还有一个或多个车辆可用于服务客户,并且每辆车有容量限制。
VRPTW的目标是找到一组最优路径,使得所有客户的需求得到满足,并且最小化总的路程和车辆的数量。解决VRPTW问题可以帮助优化物流和配送等领域的路线规划,提高效率和降低成本。
其中M是一个足够大的正数。
这个数学模型描述了VRPTW问题的基本约束和目标,您可以根据具体情况进行进一步的修改和扩展。
- import cplex
- from cplex.exceptions import CplexError
-
- # 读取数据
- def read_data(filename):
- # 从文件中读取服务点、客户的位置
- data = {}
- node_list = []
- with open(filename, 'rt') as f:
- count = 1
- for line in f:
- if count == 5:
- vehicle_num, vehicle_capacity = line.split()
- vehicle_num = int(vehicle_num)
- vehicle_capacity = int(vehicle_capacity)
- elif count >= 10:
- node_list.append(line.split())
- count += 1
-
- for item in node_list:
- customer_id = int(item[0])
- x = float(item[1])
- y = float(item[2])
- demand = float(item[3])
- ready_time = float(item[4])
- due_date = float(item[5])
- service_time = float(item[6])
- data[customer_id] = {
- 'x': x,
- 'y': y,
- 'demand': demand,
- 'ready_time': ready_time,
- 'due_date': due_date,
- 'service_time': service_time
- }
-
- return data, vehicle_num, vehicle_capacity
-
- # 构建VRPTW模型
- def build_model(data, num_vehicles, vehicle_capacity):
- model = cplex.Cplex()
- model.objective.set_sense(model.objective.sense.minimize)
-
- # 创建决策变量
- x_vars = {}
- for i in data:
- for j in data:
- for k in range(1, num_vehicles+1):
- x_vars[(i, j, k)] = model.variables.get_num()
- model.variables.add(obj=[data[i]['x']-data[j]['x'], data[i]['y']-data[j]['y']], lb=[0.0], ub=[1.0], types=['B'])
-
- t_vars = {}
- for i in data:
- t_vars[i] = model.variables.get_num()
- model.variables.add(obj=[0.0], lb=[data[i]['ready_time']], ub=[data[i]['due_date']], types=['C'])
-
- # 添加约束条件
- # 每个客户节点必须且仅能被访问一次
- for i in data:
- model.linear_constraints.add(lin_expr=[[x_vars[(i, j, k)] for j in data] + [x_vars[(j, i, k)] for j in data]], senses=['E'], rhs=[1.0])
-
- # 每个车辆的路径必须从仓库出发并返回仓库
- for k in range(1, num_vehicles+1):
- model.linear_constraints.add(lin_expr=[[x_vars[(0, j, k)] for j in data]], senses=['E'], rhs=[1.0])
- model.linear_constraints.add(lin_expr=[[x_vars[(i, 0, k)] for i in data]], senses=['E'], rhs=[1.0])
-
- # 车辆容量限制
- for j in data:
- for k in range(1, num_vehicles+1):
- model.linear_constraints.add(lin_expr=[[x_vars[(i, j, k)] for i in data]], senses=['L'], rhs=[data[j]['demand']])
-
- # 时间窗口约束
- M = max(data[j]['due_date'] for j in data) + max(data[j]['service_time'] for j in data)
- for i in data:
- for j in data:
- for k in range(1, num_vehicles+1):
- model.linear_constraints.add(lin_expr=[[t_vars[i], data[i]['service_time'], data[i]['demand'], -M, x_vars[(i, j, k)], t_vars[j]]], senses=['L'], rhs=[data[j]['due_date']])
-
- return model
-
- # 解决VRPTW模型
- def solve_model(model, data, num_vehicles):
- try:
- model.solve()
- solution = model.solution
- if solution.get_status() == solution.status.optimal:
- print('最优解已找到')
- print('目标函数值:', solution.get_objective_value())
- print('路径安排:')
- for k in range(1, num_vehicles+1):
- print('车辆', k, ':')
- for i in data:
- for j in data:
- if solution.get_values(x_vars[(i, j, k)]) > 0.9:
- print(i, '->', j)
- print()
- else:
- print('求解失败')
- except CplexError as e:
- print('求解失败:', e)
-
- # 主函数
- if __name__ == '__main__':
- data, num_vehicles, vehicle_capacity = read_data('C101.txt')
- model = build_model(data, num_vehicles, vehicle_capacity)
- solve_model(model, data, num_vehicles)
- import numpy as np
- import random
-
- # 读取数据
- def read_data(filename):
- # 从文件中读取服务点、客户的位置
- data = {}
- node_list = []
- with open(filename, 'rt') as f:
- count = 1
- for line in f:
- if count == 5:
- vehicle_num, vehicle_capacity = line.split()
- vehicle_num = int(vehicle_num)
- vehicle_capacity = int(vehicle_capacity)
- elif count >= 10:
- node_list.append(line.split())
- count += 1
-
- for item in node_list:
- customer_id = int(item[0])
- x = float(item[1])
- y = float(item[2])
- demand = float(item[3])
- ready_time = float(item[4])
- due_date = float(item[5])
- service_time = float(item[6])
- data[customer_id] = {
- 'x': x,
- 'y': y,
- 'demand': demand,
- 'ready_time': ready_time,
- 'due_date': due_date,
- 'service_time': service_time
- }
-
- return data, vehicle_num, vehicle_capacity
-
- # 计算两个节点之间的距离
- def calculate_distance(node1, node2):
- return np.sqrt((node1['x'] - node2['x'])**2 + (node1['y'] - node2['y'])**2)
-
- # 计算节点间的信息素初始值
- def initialize_pheromone(data):
- num_nodes = len(data)
- pheromone = np.ones((num_nodes, num_nodes))
- return pheromone
-
- # 更新信息素
- def update_pheromone(pheromone, ants, best_ant, evaporation_rate, Q):
- pheromone *= (1 - evaporation_rate) # 蒸发信息素
- for ant in ants:
- for i in range(len(ant['path']) - 1):
- node1 = ant['path'][i]
- node2 = ant['path'][i+1]
- pheromone[node1][node2] += Q / ant['total_distance'] # 更新路径上的信息素
- best_path = best_ant['path']
- for i in range(len(best_path) - 1):
- node1 = best_path[i]
- node2 = best_path[i+1]
- pheromone[node1][node2] += Q / best_ant['total_distance'] # 更新最佳路径上的信息素
- return pheromone
-
- # 选择下一个节点
- def select_next_node(pheromone, current_node, available_nodes, alpha, beta):
- probabilities = []
- total = 0
- for node in available_nodes:
- pheromone_value = pheromone[current_node][node]
- distance_value = 1 / calculate_distance(data[current_node], data[node])
- probability = (pheromone_value**alpha) * (distance_value**beta)
- probabilities.append(probability)
- total += probability
- probabilities = [p / total for p in probabilities]
- next_node = random.choices(available_nodes, probabilities)[0]
- return next_node
-
- # 构建初始路径
- def construct_initial_path(pheromone, alpha, beta):
- num_nodes = len(data)
- current_node = 0 # 仓库节点
- available_nodes = list(range(1, num_nodes)) # 可选节点
- path = [current_node]
- total_distance = 0
-
- while available_nodes:
- next_node = select_next_node(pheromone, current_node, available_nodes, alpha, beta)
- path.append(next_node)
- total_distance += calculate_distance(data[current_node], data[next_node])
- available_nodes.remove(next_node)
- current_node = next_node
-
- path.append(0) # 返回仓库节点
- total_distance += calculate_distance(data[current_node], data[0])
-
- return path, total_distance
-
- # 更新最佳路径
- def update_best_path(path, total_distance, best_ant):
- if total_distance < best_ant['total_distance']:
- best_ant['path'] = path
- best_ant['total_distance'] = total_distance
-
- # 蚁群算法求解VRPTW
- def solve_vrptw(data, num_vehicles, vehicle_capacity, num_ants, num_iterations, alpha, beta, evaporation_rate, Q):
- num_nodes = len(data)
- best_ant = {
- 'path': [],
- 'total_distance': float('inf')
- }
- pheromone = initialize_pheromone(data)
-
- for _ in range(num_iterations):
- ants = []
- for _ in range(num_ants):
- ant = {}
- ant['path'], ant['total_distance'] = construct_initial_path(pheromone, alpha, beta)
- ants.append(ant)
- update_best_path(ant['path'], ant['total_distance'], best_ant)
-
- pheromone = update_pheromone(pheromone, ants, best_ant, evaporation_rate, Q)
-
- return best_ant['path'], best_ant['total_distance']
-
- # 主函数
- if __name__ == '__main__':
- data, num_vehicles, vehicle_capacity = read_data('C101.txt')
- num_ants = 10 # 蚂蚁数量
- num_iterations = 100 # 迭代次数
- alpha = 1 # 信息素重要程度参数
- beta = 2 # 距离的重要程度参数
- evaporation_rate = 0.5 # 信息素蒸发率
- Q = 100 # 信息素增强强度
-
- best_path, best_distance = solve_vrptw(data, num_vehicles, vehicle_capacity, num_ants, num_iterations, alpha, beta, evaporation_rate, Q)
-
- print('最佳路径:', best_path)
- print('最佳路径总距离:', best_distance)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。