lead/tsp_data/tsp_algo.py

414 lines
13 KiB
Python
Raw Normal View History

2025-03-17 16:40:01 +08:00
import numpy as np
from typing import List
def greedy_tsp(distances: np.ndarray) -> List[int]:
"""贪心算法求解TSP
Args:
distances: 距离矩阵
Returns:
访问顺序列表
"""
n = len(distances)
unvisited = set(range(1, n)) # 未访问的城市集合
path = [0] # 从城市0开始
while unvisited:
last = path[-1]
# 找到距离最后一个城市最近的未访问城市
next_city = min(unvisited, key=lambda x: distances[last][x])
path.append(next_city)
unvisited.remove(next_city)
return path
def nearest_neighbor_tsp(distances: np.ndarray) -> List[int]:
"""最近邻算法求解TSP
Args:
distances: 距离矩阵
Returns:
访问顺序列表
"""
n = len(distances)
unvisited = set(range(1, n))
path = [0] # 从城市0开始
while unvisited:
curr = path[-1]
# 找到距离当前城市最近的未访问城市
next_city = min(unvisited, key=lambda x: distances[curr][x])
path.append(next_city)
unvisited.remove(next_city)
return path
def insertion_tsp(distances: np.ndarray) -> List[int]:
"""插入法求解TSP
Args:
distances: 距离矩阵
Returns:
访问顺序列表
"""
n = len(distances)
# 初始化包含前两个城市的回路
path = [0, np.argmin(distances[0][1:])+1]
unvisited = set(range(1, n)) - {path[1]}
while unvisited:
min_increase = float('inf')
best_pos = -1
best_city = -1
# 尝试将每个未访问城市插入到当前路径的每个可能位置
for city in unvisited:
for i in range(len(path)):
j = (i + 1) % len(path)
# 计算插入后的路径增量
increase = (distances[path[i]][city] +
distances[city][path[j]] -
distances[path[i]][path[j]])
if increase < min_increase:
min_increase = increase
best_pos = i + 1
best_city = city
# 将最佳城市插入到最佳位置
path.insert(best_pos, best_city)
unvisited.remove(best_city)
return path
def tsp_01(distances: np.ndarray) -> List[int]:
"""动态规划+2-opt优化求解TSP(内存优化版)
Args:
distances: 距离矩阵
Returns:
访问顺序列表
"""
from itertools import combinations
from typing import List
import numpy as np
n = len(distances)
# 使用字典存储dp表,只保存必要的状态
dp = {}
dp[(1, 0)] = 0
# 动态规划部分,使用位运算加速
for size in range(2, n + 1):
# 提前计算所有可能的子集
subsets = list(combinations(range(n), size))
for subset in subsets:
mask = sum(1 << i for i in subset)
for v in subset:
if v == 0:
continue
prev_mask = mask ^ (1 << v)
min_dist = float('inf')
# 只遍历必要的前驱节点
for u in subset:
if u != v and (prev_mask & (1 << u)):
curr_dist = dp.get((prev_mask, u), float('inf')) + distances[u][v]
min_dist = min(min_dist, curr_dist)
if min_dist != float('inf'):
dp[(mask, v)] = min_dist
# 重建路径,使用贪心策略
final_mask = (1 << n) - 1
last_city = min(range(1, n),
key=lambda u: dp.get((final_mask, u), float('inf')) + distances[u][0])
path = [0]
curr_mask = final_mask
curr_city = last_city
# 使用集合加速查找
remaining = set(range(n))
remaining.remove(0)
while remaining:
path.append(curr_city)
remaining.remove(curr_city)
prev_mask = curr_mask ^ (1 << curr_city)
curr_city = min(remaining,
key=lambda u: dp.get((prev_mask, u), float('inf')) + distances[u][curr_city])
curr_mask = prev_mask
path.append(curr_city)
# 优化版2-opt
improved = True
best_dist = float('inf')
while improved:
improved = False
curr_dist = sum(distances[path[i]][path[i+1]] for i in range(n-1)) + distances[path[-1]][path[0]]
if curr_dist < best_dist:
best_dist = curr_dist
for i in range(1, n-2):
for j in range(i+2, n):
delta = (distances[path[i-1]][path[j-1]] + distances[path[i]][path[j]] -
distances[path[i-1]][path[i]] - distances[path[j-1]][path[j]])
if delta < 0:
path[i:j] = reversed(path[i:j])
improved = True
break
if improved:
break
return path
def tsp_02(distances: np.ndarray) -> List[int]:
"""动态规划+简化遗传算法求解TSP
Args:
distances: 距离矩阵
Returns:
访问顺序列表
"""
from typing import List
import numpy as np
import random
n = len(distances)
# 使用贪心算法生成初始解
path = list(range(n))
for i in range(n-1):
min_j = min(range(i+1, n),
key=lambda j: distances[path[i]][path[j]])
path[i+1], path[min_j] = path[min_j], path[i+1]
# 简化的遗传算法
pop_size = 20 # 减小种群大小
generations = 100 # 减少迭代次数
population = [path[:]]
# 生成初始种群
for _ in range(pop_size - 1):
new_path = path[:]
i, j = random.sample(range(1, n), 2)
new_path[i], new_path[j] = new_path[j], new_path[i]
population.append(new_path)
for _ in range(generations):
# 选择最优的一半
population.sort(key=lambda x: sum(distances[x[i]][x[i+1]]
for i in range(n-1)) + distances[x[-1]][x[0]])
population = population[:pop_size//2]
# 通过交叉生成新解
while len(population) < pop_size:
p1, p2 = random.sample(population, 2)
cut = random.randint(1, n-2)
child = p1[:cut]
child.extend(x for x in p2 if x not in child)
population.append(child)
return min(population,
key=lambda x: sum(distances[x[i]][x[i+1]]
for i in range(n-1)) + distances[x[-1]][x[0]])
def tsp_03(distances: np.ndarray) -> List[int]:
"""快速模拟退火求解TSP
Args:
distances: 距离矩阵
Returns:
访问顺序列表
"""
from typing import List
import numpy as np
import random
import math
n = len(distances)
# 使用贪心算法生成初始解
route = list(range(n))
for i in range(n-1):
min_j = min(range(i+1, n),
key=lambda j: distances[route[i]][route[j]])
route[i+1], route[min_j] = route[min_j], route[i+1]
current_cost = sum(distances[route[i]][route[i+1]]
for i in range(n-1)) + distances[route[-1]][route[0]]
# 快速降温的模拟退火
temp = 100.0
cooling = 0.95
iterations = 50 # 减少迭代次数
while temp > 0.1:
for _ in range(iterations):
i, j = random.sample(range(1, n), 2)
new_route = route[:]
new_route[i], new_route[j] = new_route[j], new_route[i]
new_cost = sum(distances[new_route[k]][new_route[k+1]]
for k in range(n-1)) + distances[new_route[-1]][new_route[0]]
if new_cost < current_cost or random.random() < math.exp((current_cost - new_cost) / temp):
route = new_route
current_cost = new_cost
temp *= cooling
return route
def two_opt(route, distances):
"""简化版2-opt优化"""
improved = True
while improved:
improved = False
for i in range(1, len(route) - 2):
if improved:
break
for j in range(i + 2, len(route)):
old_dist = (distances[route[i-1]][route[i]] +
distances[route[j-1]][route[j]])
new_dist = (distances[route[i-1]][route[j-1]] +
distances[route[i]][route[j]])
if new_dist < old_dist:
route[i:j] = reversed(route[i:j])
improved = True
break
return route
def calculate_cost(route, distances):
"""计算路径总成本"""
return sum(distances[route[i]][route[(i + 1) % len(route)]]
for i in range(len(route)))
def tsp_04(distances):
"""
高性能TSP求解算法,结合多种优化策略:
1. 贪心构造初始解
2. 快速模拟退火
3. 2-opt局部搜索
"""
import random
import math
n = len(distances)
# 贪心构造初始解
unvisited = set(range(1, n))
current = 0
route = [0]
while unvisited:
next_city = min(unvisited, key=lambda x: distances[current][x])
route.append(next_city)
unvisited.remove(next_city)
current = next_city
# 快速模拟退火
temp = 100.0
cooling = 0.95
iterations = 30
current_cost = calculate_cost(route, distances)
best_route = route[:]
best_cost = current_cost
while temp > 0.1:
for _ in range(iterations):
# 随机交换两个城市
i, j = random.sample(range(1, n), 2)
new_route = route[:]
new_route[i], new_route[j] = new_route[j], new_route[i]
new_cost = calculate_cost(new_route, distances)
if new_cost < current_cost or random.random() < math.exp((current_cost - new_cost) / temp):
route = new_route
current_cost = new_cost
if new_cost < best_cost:
best_route = new_route[:]
best_cost = new_cost
temp *= cooling
# 2-opt局部优化
best_route = two_opt(best_route, distances)
return best_route
def tsp_05(distances):
"""
基于插入法的TSP优化算法:
1. 插入法构造初始解
2. 快速模拟退火
3. 2-opt局部搜索
"""
import random
import math
n = len(distances)
# 插入法构造初始解
route = [0, 1] # 从城市0和1开始
unvisited = set(range(2, n))
while unvisited:
# 找到最佳插入位置和待插入城市
min_increase = float('inf')
best_pos = 0
best_city = 0
for city in unvisited:
# 尝试所有可能的插入位置
for i in range(len(route)):
if i == len(route) - 1:
increase = (distances[route[i]][city] +
distances[city][route[0]] -
distances[route[i]][route[0]])
else:
increase = (distances[route[i]][city] +
distances[city][route[i+1]] -
distances[route[i]][route[i+1]])
if increase < min_increase:
min_increase = increase
best_pos = i + 1
best_city = city
# 在最佳位置插入城市
route.insert(best_pos, best_city)
unvisited.remove(best_city)
# 快速模拟退火
temp = 100.0
cooling = 0.95
iterations = 30
current_cost = calculate_cost(route, distances)
best_route = route[:]
best_cost = current_cost
while temp > 0.1:
for _ in range(iterations):
# 随机交换两个城市
i, j = random.sample(range(1, n), 2)
new_route = route[:]
new_route[i], new_route[j] = new_route[j], new_route[i]
new_cost = calculate_cost(new_route, distances)
if new_cost < current_cost or random.random() < math.exp((current_cost - new_cost) / temp):
route = new_route
current_cost = new_cost
if new_cost < best_cost:
best_route = new_route[:]
best_cost = new_cost
temp *= cooling
# 2-opt局部优化
best_route = two_opt(best_route, distances)
return best_route