课设终结者之TSP(ortools)(各种改进的遗传算法)(源码)

3 篇文章 0 订阅
3 篇文章 0 订阅

本人作为学生,很没有耐性,往往我看代码都会不在乎理论部分(真想看理论部分的人基本都会直接上百度或者看论文)。当你来到此处,证明你和我一样,不需要长篇大论,想要的不过是一个能跑的代码,并且能够可视化就更加无敌了。

单TSP

废话不多说,直接上效果图(google的ortools算法)

当点的数量为9

是不是觉得这个太简单了,因为点比较少,那我尝试多增加一些点。

点的数量为50

这个路径效果尚可,实用python运行,仅需0.87s即可获得结果,不得不说这是一个非常不错的算法。效果可以说是秒杀一众智能算法(启发式算法)

首先安装ortools包,直接pip install ortools就可以安装。

代码

import time
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import random
import math
import matplotlib.pyplot as plt
def calculate_distance_matrix(coordinates):
    num_points = len(coordinates)
    distance_matrix = [[0] * num_points for _ in range(num_points)]

    for i in range(num_points):
        for j in range(num_points):
            if i != j:
                x1, y1 = coordinates[i]
                x2, y2 = coordinates[j]

                distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
                distance_matrix[i][j] = distance
    return distance_matrix
def create_data_model(dis):
    """Stores the data for the problem."""
    data = {}
    data['distance_matrix'] = dis
    data['num_vehicles'] = 1  # Number of salesmen/travelers
    data['depots'] = 0
    return data

def print_solution(data, manager, routing, solution):
    rout = []
    """Prints solution on console."""
    max_route_distance = 0
    for vehicle_id in range(data['num_vehicles']):
        curroute = []
        index = routing.Start(vehicle_id)
        plan_output = f'Route for vehicle {vehicle_id}:\n'
        route_distance = 0
        while not routing.IsEnd(index):
            # print()
            curroute.append(manager.IndexToNode(index))
            plan_output += f' {manager.IndexToNode(index)} -> '
            previous_index = index
            index = solution.Value(routing.NextVar(index))
            route_distance += routing.GetArcCostForVehicle(previous_index, index, vehicle_id)
        rout.append(curroute)
        plan_output += f'{manager.IndexToNode(index)}\n'
        plan_output += f'Distance of the route: {route_distance}m\n'
        print(plan_output)
        max_route_distance = max(max_route_distance, route_distance)
    print(f'Maximum of the route distances: {max_route_distance}m')
    return rout
##进行坐标的替换
def change(rout,point):
    if len(rout) == 1:
        rout1 = rout[0]
        result = [point[index] for index in rout1]
        return result
    else:
        result = []
        for currout in rout:
            curresult = [point[index] for index in currout]
            result.append(curresult)
        return result
def generate_random_points(num_points, value_range):
    """
    生成一个随机点的列表。
    参数:
    num_points : int - 生成点的数量
    value_range: (int, int) - 点坐标的取值范围,形如 (最小值, 最大值)
    返回:
    points : list of tuples - 生成的点列表,每个点表示为 (x, y)
    """
    points = []
    min_val = 0
    max_val = value_range  # 解包取值范围为最小值和最大值
    for _ in range(num_points):
        x = int(random.randint(min_val, max_val))  # 随机生成 x 坐标
        y = int(random.randint(min_val, max_val))  # 随机生成 y 坐标
        points.append((x, y))

    return points
def ortools(Point):
    t1 = time.time()
    dis = calculate_distance_matrix(Point)
    # Instantiate the data problem.
    data = create_data_model(dis)
    # Create the routing index manager.
    manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
                                           data['num_vehicles'],
                                           data['depots']
                                           )
    # Create Routing Model.
    routing = pywrapcp.RoutingModel(manager)
    # Define the distance callback.
    def distance_callback(from_index, to_index):
        """Returns the distance between the two nodes."""
        from_node = manager.IndexToNode(from_index)
        to_node = manager.IndexToNode(to_index)
        return data['distance_matrix'][from_node][to_node]

    transit_callback_index = routing.RegisterTransitCallback(distance_callback)
    routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
    dimension_name = 'Distance'
    routing.AddDimension(
        transit_callback_index,
        0,  # no slack
        3000,  # maximum distance per vehicle
        True,  # start cumul to zero
        dimension_name)
    distance_dimension = routing.GetDimensionOrDie(dimension_name)
    distance_dimension.SetGlobalSpanCostCoefficient(100)

    # Setting first solution heuristic.
    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (
        routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

    # Solve the problem.
    solution = routing.SolveWithParameters(search_parameters)
    t2 = time.time()
    print("花费了: ", t2 - t1, " s")
    # Print solution on console.
    if solution:
        rout = print_solution(data, manager, routing, solution)
        result = change(rout, Point)
        print(result)
        # 确保起点和终点相连
        if result[0] != result[-1]:
            result.append(result[0])
        plt.figure()
        # 绘制路径
        x, y = zip(*result)  # 将点的坐标转置为两个分离的列表
        plt.plot(x, y, 'o-', color='blue')  # 'o-' 表示以圆圈形式绘制点并连接它们
        # 设置图形属性
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.title('Connected Path')
        # 显示图形
        plt.show()
if __name__ == '__main__':
    # Point = [(1, 1), (2, 3), (5, 2), (7, 8), (9, 5), (8, 3), (4, 7), (6, 1), (3, 6)]  ##点的示例
    Point = generate_random_points(50,20)
    ortools(Point)

多TSP

当点的数量为30

这种效果已经很理想了(肉眼可见的理想)

下面直接放源码(直接就能跑)

import time
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import random
import math

##计算距离矩阵
def calculate_distance_matrix(coordinates):
    num_points = len(coordinates)
    distance_matrix = [[0] * num_points for _ in range(num_points)]

    for i in range(num_points):
        for j in range(num_points):
            if i != j:
                x1, y1 = coordinates[i]
                x2, y2 = coordinates[j]

                distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
                distance_matrix[i][j] = distance

    return distance_matrix


def create_data_model(dis):
    """Stores the data for the problem."""
    data = {}
    data['distance_matrix'] = dis
    data['num_vehicles'] = 2  # Number of salesmen/travelers
    data['starts'] = [0, 0]  # Starting nodes for each vehicle
    data['ends'] = [0, 0]  # Ending nodes for each vehicle, can be different from starts if needed
    return data

def print_solution(data, manager, routing, solution):
    rout = []
    """Prints solution on console."""
    max_route_distance = 0
    for vehicle_id in range(data['num_vehicles']):
        curroute = []
        index = routing.Start(vehicle_id)
        plan_output = f'Route for vehicle {vehicle_id}:\n'
        route_distance = 0
        while not routing.IsEnd(index):
            curroute.append(manager.IndexToNode(index))
            plan_output += f' {manager.IndexToNode(index)} -> '
            previous_index = index
            index = solution.Value(routing.NextVar(index))
            route_distance += routing.GetArcCostForVehicle(previous_index, index, vehicle_id)
        rout.append(curroute)
        plan_output += f'{manager.IndexToNode(index)}\n'
        plan_output += f'Distance of the route: {route_distance}m\n'
        print(plan_output)
        max_route_distance = max(max_route_distance, route_distance)
    print(f'Maximum of the route distances: {max_route_distance}m')
    return rout
##进行坐标的替换
def change(rout,point):
    if len(rout) == 1:
        rout1 = rout[0]
        result = [point[index] for index in rout1]
        return result
    else:
        result = []
        for currout in rout:
            curresult = [point[index] for index in currout]
            result.append(curresult)
        return result
def generate_random_points(num_points, value_range):
    """
    生成一个随机点的列表。
    参数:
    num_points : int - 生成点的数量
    value_range: (int, int) - 点坐标的取值范围,形如 (最小值, 最大值)
    返回:
    points : list of tuples - 生成的点列表,每个点表示为 (x, y)
    """
    points = []
    min_val = 0
    max_val = value_range  # 解包取值范围为最小值和最大值
    for _ in range(num_points):
        x = int(random.randint(min_val, max_val))  # 随机生成 x 坐标
        y = int(random.randint(min_val, max_val))  # 随机生成 y 坐标
        points.append((x, y))
    return points
def ortools(Point):
    dis = calculate_distance_matrix(Point)
    # Instantiate the data problem.
    data = create_data_model(dis)
    # Create the routing index manager.
    manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
                                           data['num_vehicles'],
                                           data['starts'],
                                           data['ends']
                                           )
    # Create Routing Model.
    routing = pywrapcp.RoutingModel(manager)

    # Define the distance callback.
    def distance_callback(from_index, to_index):
        """Returns the distance between the two nodes."""
        from_node = manager.IndexToNode(from_index)
        to_node = manager.IndexToNode(to_index)
        return data['distance_matrix'][from_node][to_node]

    transit_callback_index = routing.RegisterTransitCallback(distance_callback)

    # Define cost of each arc.
    routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

    # Add Distance constraint.
    dimension_name = 'Distance'
    routing.AddDimension(
        transit_callback_index,
        0,  # no slack
        3000,  # maximum distance per vehicle
        True,  # start cumul to zero
        dimension_name)
    distance_dimension = routing.GetDimensionOrDie(dimension_name)
    distance_dimension.SetGlobalSpanCostCoefficient(100)

    # Setting first solution heuristic.
    search_parameters = pywrapcp.DefaultRoutingSearchParameters()
    search_parameters.first_solution_strategy = (
        routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

    # Solve the problem.
    solution = routing.SolveWithParameters(search_parameters)

    # Print solution on console.
    if solution:
        rout = print_solution(data, manager, routing, solution)
        result = change(rout, Point)
        print(result)
        import matplotlib.pyplot as plt

        colors = ['blue', 'green', 'red', 'cyan', 'magenta', 'yellow', 'black', 'purple', 'orange', 'brown']
        # 二维数组
        plt.figure(figsize=(10, 6))  # 可以根据需要调整图形大小

        # 绘制每条路径
        for idx, line in enumerate(result):
            # 确保起点和终点相连
            if line[0] != line[-1]:
                line.append(line[0])

            # 绘制连接线段,从颜色列表中循环选择颜色
            color = colors[idx % len(colors)]
            x, y = zip(*line)  # 将点的坐标转置为两个分离的列表
            plt.plot(x, y, 'o-', color=color, label=f'Path {idx + 1}')  # 使用 'o-' 表示点和线

        # 设置图形属性
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.title('Connected Paths')
        plt.legend()  # 显示图例

        # 显示图形
        plt.show()
if __name__ == '__main__':
    # Point = [(1, 1), (2, 3), (5, 2), (7, 8), (9, 5), (8, 3), (4, 7), (6, 1), (3, 6)]
    Point = generate_random_points(30,50)
    ortools(Point)

茶饭闲谈

本人的研究方向为任务分配,实际上就是解决复杂约束条件下的优化问题,本人刚开始也是从TSP入手(实际上两者没多大区别),智能算法目前能够较好的解决这个问题。本人还有许多自己写的算法(包括优化),后续都会公开出来,比如对简单的遗传算法进行多种改进(纯自己创新),虽然效果还凑活,但由于是原创,网上没有,所以完全可以当做课设。

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

主打一个实用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值