[python] use CW algorithm to solve TSP problem

Tips: The following information is from chatgpt, and the following content is only used as a personal study record


1. Use the CW algorithm to solve the TSP problem

The TSP problem refers to the Traveling Salesman Problem, which is a classic combinatorial optimization problem. The problem can be described as: Given a map containing n cities, the traveling salesman needs to start from one city, pass through all the cities in turn, and finally return to the starting city. The traveling salesman must go through all the cities, and each city can only go through once. The traveling salesman is free to choose any city as the starting point, and asks how to plan the travel route so that the total distance is the shortest

The CW-Saving Algorithm is a heuristic algorithm for solving the Traveling Salesman Problem (TSP). Its goal is to find a Hamiltonian circuit that is as short as possible. But since the CW algorithm is an approximate algorithm, it is not guaranteed to find the minimum solution of the TSP problem, but for practical problems, its solution is usually very close to the optimal solution and has good time complexity. Moreover, the CW algorithm is also applicable to large-scale problems, which makes it very useful in practice.

Two, the code

1. Code

code show as below:

import math
# 计算两个城市之间的距离
def dist(a, b):
    return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)

# 在未访问城市中查找距离当前城市最近的城市
def find_nearest(city, cities, visited):
    nearest_dist = float('inf')
    nearest_city = None
    for c in cities:
        if c not in visited and c != city:
            d = dist(city, c)
            if d < nearest_dist:
                nearest_dist = d
                nearest_city = c
    return nearest_city, nearest_dist

# 计算每对城市之间的节约成本
def find_savings(cities):
    savings = []
    for i in range(len(cities)):
        for j in range(i+1, len(cities)):
            d = dist(cities[i], cities[j])
            savings.append((i, j, d))
    return sorted(savings, key=lambda x: x[2], reverse=True)

# 构建城市之间的最小生成树
def minimum_spanning_tree(cities):
    mst = []
    visited = set([cities[0]])
    while len(visited) < len(cities):
        nearest_dist = float('inf')
        nearest_edge = None
        for v in visited:
            c, d = find_nearest(v, cities, visited)
            if d < nearest_dist:
                nearest_dist = d
                nearest_edge = (v, c)
        mst.append(nearest_edge)
        visited.add(nearest_edge[1])
    return mst

def find_euler_tour(mst):
    tour = []
    stack = [mst[0][0]]
    while len(stack) > 0:
        v = stack[-1]
        for e in mst:
            if e[0] == v and e[1] not in tour:
                tour.append(e[1])
                stack.append(e[1])
                break
            elif e[1] == v and e[0] not in tour:
                tour.append(e[0])
                stack.append(e[0])
                break
        else:
            stack.pop()
    return tour

def euler_to_tsp(euler_tour):
    tsp_path = [euler_tour[0]]
    for i in range(1, len(euler_tour)):
        if euler_tour[i] != tsp_path[-1]:
            tsp_path.append(euler_tour[i])
    tsp_path.append(euler_tour[0])
    return tsp_path

def solve_tsp(cities):
    # 计算节约成本
    savings = find_savings(cities)
    # 构建最小生成树
    mst = minimum_spanning_tree(cities)
    # 找到欧拉回路
    euler_tour = find_euler_tour(mst)
    # 将欧拉回路转换为TSP路径
    tsp_path = euler_to_tsp(euler_tour)
    # 计算TSP路径的总长度
    tsp_length = sum([dist(tsp_path[i], tsp_path[i+1]) for i in range(len(tsp_path)-1)])
    return tsp_path, tsp_length

main function:

if __name__ == '__main__':
    cities = [(1,1),(1,3),(2,2),(3,1),(3,3)]
    tsp_path, tsp_length=solve_tsp(cities)
    print(f'tsp_path:{
      
      tsp_path}')
    print(f'tsp_length:{
      
      tsp_length}')

2. Output

The above code can be run directly and successfully. After running the above code locally, the output is:

tsp_path:[(2, 2), (1, 1), (1, 3), (3, 1), (3, 3), (2, 2)]
tsp_length:9.656854249492381

3. City coordinates

The city coordinates can be changed at will, as needed

Guess you like

Origin blog.csdn.net/CBCY_csdn/article/details/130393559