import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
def calc_distance(city1, city2):
return np.linalg.norm(np.array(city1) - np.array(city2))
def calc_distances(cities):
n_cities = len(cities)
distances = np.zeros((n_cities, n_cities))
for i in range(n_cities):
for j in range(i + 1, n_cities):
distances[i][j] = distances[j][i] = calc_distance(cities[i], cities[j])
return distances
class AntColony:
def __init__(self, distances, n_ants, n_iterations, decay, alpha=1, beta=5, rho=0.1, Q=1):
self.distances = distances
self.pheromone = np.ones_like(distances) / len(distances)
self.n_ants = n_ants
self.n_iterations = n_iterations
self.decay = decay
self.alpha = alpha
self.beta = beta
self.rho = rho
self.Q = Q
self.shortest_path_lengths = []
def run(self):
shortest_path = None
shortest_path_length = np.inf
for _ in range(self.n_iterations):
all_paths = self.gen_all_paths()
self.spread_pheromone(all_paths)
shortest_path, shortest_path_length = self.get_shortest(all_paths, shortest_path, shortest_path_length)
self.pheromone *= (1 - self.rho)
self.shortest_path_lengths.append(shortest_path_length)
return shortest_path, shortest_path_length
def spread_pheromone(self, all_paths):
for path in all_paths:
for move in path:
self.pheromone[move] += self.Q / self.distances[move]
def gen_path_dist(self, path):
total = 0
for move in path:
total += self.distances[move]
return total
def gen_all_paths(self):
all_paths = []
for _ in range(self.n_ants):
path = self.gen_path()
all_paths.append(path)
return all_paths
def gen_path(self):
n_cities = len(self.distances)
path = []
visited = set()
start = np.random.randint(n_cities)
visited.add(start)
prev = start
for _ in range(n_cities - 1):
next_city = self.pick_city(prev, visited)
path.append((prev, next_city))
prev = next_city
visited.add(next_city)
path.append((prev, start))
return path
def pick_city(self, prev, visited):
pheromone = np.copy(self.pheromone[prev])
pheromone[list(visited)] = 0
row = pheromone ** self.alpha * (1.0 / (self.distances[prev] + 1e-6) ** self.beta)
norm_row = row / row.sum()
next_city = np.random.choice(range(len(self.distances)), 1, p=norm_row)[0]
return next_city
def get_shortest(self, all_paths, shortest_path, shortest_path_length):
for path in all_paths:
path_dist = self.gen_path_dist(path)
if path_dist < shortest_path_length:
shortest_path = [(int(a), int(b)) for (a, b) in path]
shortest_path_length = path_dist
return shortest_path, shortest_path_length
# 数据加载模块
try:
df = pd.read_excel("TSP.xlsx", header=None)
cities = df.iloc[:, [0, 1]].values
assert cities.shape[1] == 2, "坐标数据必须包含X,Y两列"
except FileNotFoundError:
print("错误:Excel文件未找到,请检查以下事项:")
print("1. 文件是否位于当前工作目录")
print("2. 文件名是否为'100个城市的坐标.xlsx'")
print("3. 文件扩展名是否正确(.xlsx)")
exit()
except Exception as e:
print(f"数据加载失败:{str(e)}")
exit()
# 计算距离矩阵
distances = calc_distances(cities)
# 参数设置
n_ants = 20
n_iterations = 1000
decay = 0.1
alpha = 1
beta = 2
rho = 0.1
Q = 1
# 创建并运行蚁群算法
ant_colony = AntColony(distances, n_ants, n_iterations, decay, alpha, beta, rho, Q)
shortest_path, shortest_path_length = ant_colony.run()
# 路径格式化函数
def format_path(path):
path_order = [int(path[0][0])] + [int(move[1]) for move in path]
if path_order[-1] == path_order[0]:
path_order = path_order[:-1]
return ','.join(map(str, path_order))
# 输出结果
print("最短路径序列:", format_path(shortest_path))
print("最短路径长度:", shortest_path_length)
# 可视化设置
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 绘制迭代曲线
plt.figure(figsize=(10, 5))
plt.plot(range(1, n_iterations + 1), ant_colony.shortest_path_lengths)
plt.xlabel('迭代次数')
plt.ylabel('路径长度')
plt.title('算法优化过程')
plt.grid(True)
plt.show()
# 路径可视化函数
def plot_path(cities, path):
path_order = [path[0][0]] + [move[1] for move in path]
x, y = cities[path_order, 0], cities[path_order, 1]
plt.figure(figsize=(12, 8))
# 绘制城市点并添加编号(从1开始)
for idx, (xi, yi) in enumerate(cities):
plt.scatter(xi, yi, color='red', s=6,zorder=2)
plt.text(xi, yi, str(idx + 1), fontsize=8,ha='center',va='bottom',
color='black',zorder=3)
# 绘制路径连线
plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
plt.plot(x, y, linestyle='-', marker='o', color='blue', linewidth=1, markersize=4, zorder=1)
plt.xlabel('X坐标', fontsize=12)
plt.ylabel('Y坐标', fontsize=12)
plt.title('TSP最优路线 城市编号(1-1000)', fontsize=14)
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
plot_path(cities, shortest_path)输出错误D:\python\space\.venv\Scripts\python.exe D:\python\space\8\6.py
D:\python\space\8\6.py:43: RuntimeWarning: divide by zero encountered in scalar divide
self.pheromone[move] += self.Q / self.distances[move]
D:\python\space\8\6.py:77: RuntimeWarning: invalid value encountered in divide
norm_row = row / row.sum()
Traceback (most recent call last):
File "D:\python\space\8\6.py", line 118, in <module>
shortest_path, shortest_path_length = ant_colony.run()
^^^^^^^^^^^^^^^^
File "D:\python\space\8\6.py", line 33, in run
all_paths = self.gen_all_paths()
^^^^^^^^^^^^^^^^^^^^
File "D:\python\space\8\6.py", line 54, in gen_all_paths
path = self.gen_path()
^^^^^^^^^^^^^^^
File "D:\python\space\8\6.py", line 66, in gen_path
next_city = self.pick_city(prev, visited)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\python\space\8\6.py", line 78, in pick_city
next_city = np.random.choice(range(len(self.distances)), 1, p=norm_row)[0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "numpy\\random\\mtrand.pyx", line 990, in numpy.random.mtrand.RandomState.choice
ValueError: probabilities contain NaN 修改代码正确,提供修改之后的完整代码可直接运行
最新发布