本文目录导读:

我来详细讲解如何使用NetworkX库解决旅行商问题(TSP)。
安装必要的库
pip install networkx numpy matplotlib
基础案例:完全图上的TSP
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
from itertools import permutations
def create_tsp_graph(cities, distances):
"""创建TSP问题的完全图"""
G = nx.complete_graph(len(cities))
# 添加城市名称属性
city_labels = {i: city for i, city in enumerate(cities)}
nx.set_node_attributes(G, city_labels, 'name')
# 添加边权重(距离)
for i in range(len(cities)):
for j in range(i+1, len(cities)):
G[i][j]['weight'] = distances[i][j]
return G
def brute_force_tsp(G):
"""暴力求解TSP(小规模数据用)"""
nodes = list(G.nodes())
if len(nodes) > 8:
print("节点数量过多,建议使用近似算法")
return None, float('inf')
best_path = None
min_distance = float('inf')
# 固定起点为0,减少计算量
start_node = nodes[0]
other_nodes = nodes[1:]
for perm in permutations(other_nodes):
path = [start_node] + list(perm)
distance = 0
# 计算路径总距离
for i in range(len(path)):
current = path[i]
next_node = path[(i + 1) % len(path)]
distance += G[current][next_node]['weight']
if distance < min_distance:
min_distance = distance
best_path = path
return best_path, min_distance
def nearest_neighbor_tsp(G, start_node=0):
"""最近邻近似算法"""
unvisited = set(G.nodes())
current = start_node
path = [current]
unvisited.remove(current)
total_distance = 0
while unvisited:
# 找到最近的未访问节点
nearest = min(unvisited, key=lambda x: G[current][x]['weight'])
total_distance += G[current][nearest]['weight']
current = nearest
path.append(current)
unvisited.remove(current)
# 返回起点
total_distance += G[current][start_node]['weight']
path.append(start_node)
return path, total_distance
def visualize_tsp_path(G, path, title="TSP Solution"):
"""可视化TSP路径"""
pos = nx.spring_layout(G, seed=42)
plt.figure(figsize=(12, 8))
# 绘制所有边(浅色)
nx.draw_networkx_edges(G, pos, alpha=0.2, edge_color='gray')
# 绘制路径边
path_edges = [(path[i], path[i+1]) for i in range(len(path)-1)]
nx.draw_networkx_edges(G, pos, edgelist=path_edges,
edge_color='red', width=2, alpha=0.8)
# 绘制节点
nx.draw_networkx_nodes(G, pos, node_size=500, node_color='lightblue')
nx.draw_networkx_labels(G, pos, labels=nx.get_node_attributes(G, 'name'))
# 添加边权重标签
edge_labels = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels, font_size=8)
plt.title(title)
plt.axis('off')
return plt
# 示例:中国主要城市
cities = ['北京', '上海', '广州', '深圳', '成都', '武汉']
# 城市间距离矩阵(单位:公里)
distances = [
[0, 1215, 1888, 1947, 1542, 1051], # 北京
[1215, 0, 1210, 1060, 1660, 688], # 上海
[1888, 1210, 0, 130, 1240, 830], # 广州
[1947, 1060, 130, 0, 1350, 900], # 深圳
[1542, 1660, 1240, 1350, 0, 980], # 成都
[1051, 688, 830, 900, 980, 0] # 武汉
]
# 创建图
G = create_tsp_graph(cities, distances)
# 暴力求解
print("暴力求解TSP:")
best_path, min_distance = brute_force_tsp(G)
if best_path:
city_names = [cities[i] for i in best_path]
print(f"最优路径: {' -> '.join(city_names)}")
print(f"总距离: {min_distance:.1f} 公里")
# 最近邻算法
print("\n最近邻近似算法:")
path_nn, dist_nn = nearest_neighbor_tsp(G, 0)
city_names_nn = [cities[i] for i in path_nn]
print(f"路径: {' -> '.join(city_names_nn)}")
print(f"总距离: {dist_nn:.1f} 公里")
# 可视化
visualize_tsp_path(G, best_path if best_path else path_nn,
"TSP最优路径 (暴力求解)")
plt.show()
2-opt优化算法
def two_opt_improvement(G, path):
"""2-opt局部搜索优化"""
improved = True
best_path = path.copy()
# 去掉最后一个节点(回到起点的重复)
if best_path[0] == best_path[-1]:
best_path = best_path[:-1]
n = len(best_path)
while improved:
improved = False
for i in range(1, n - 1):
for j in range(i + 1, n):
# 计算当前路径距离
current_distance = (
G[best_path[i-1]][best_path[i]]['weight'] +
G[best_path[j-1]][best_path[j]]['weight']
)
# 计算交换后的距离
new_distance = (
G[best_path[i-1]][best_path[j-1]]['weight'] +
G[best_path[i]][best_path[j]]['weight']
)
if new_distance < current_distance:
# 交换路径段
best_path = best_path[:i] + best_path[i:j][::-1] + best_path[j:]
improved = True
# 如果优化了,重置循环
if improved:
continue
# 添加回到起点的节点
best_path.append(best_path[0])
return best_path
def calculate_total_distance(G, path):
"""计算路径总距离"""
total = 0
for i in range(len(path)-1):
total += G[path[i]][path[i+1]]['weight']
return total
# 使用2-opt优化
print("\n使用2-opt优化的最近邻算法:")
initial_path, _ = nearest_neighbor_tsp(G, 0)
improved_path = two_opt_improvement(G, initial_path)
improved_distance = calculate_total_distance(G, improved_path)
city_names_opt = [cities[i] for i in improved_path]
print(f"初始路径: {' -> '.join([cities[i] for i in initial_path])}")
print(f"初始距离: {calculate_total_distance(G, initial_path):.1f} 公里")
print(f"优化后路径: {' -> '.join(city_names_opt)}")
print(f"优化后距离: {improved_distance:.1f} 公里")
print(f"优化比例: {(1 - improved_distance/calculate_total_distance(G, initial_path))*100:.1f}%")
# 可视化优化后的路径
visualize_tsp_path(G, improved_path, "TSP优化后路径 (2-opt)")
plt.show()
使用贪心算法构建初始解
def greedy_initial_solution(G):
"""贪心算法构建初始解"""
n = len(G.nodes())
edges = []
# 获取所有边并按权重排序
for u, v, data in G.edges(data=True):
edges.append((data['weight'], u, v))
edges.sort() # 按权重升序排序
# Kruskal算法构建最小生成树
parent = list(range(n))
def find(x):
while parent[x] != x:
parent[x] = parent[parent[x]]
x = parent[x]
return x
def union(x, y):
px, py = find(x), find(y)
if px != py:
parent[px] = py
return True
return False
mst_edges = []
for weight, u, v in edges:
if union(u, v):
mst_edges.append((u, v, weight))
# 从MST构建路径(深度优先遍历)
mst_graph = nx.Graph()
mst_graph.add_edges_from([(u, v, {'weight': w}) for u, v, w in mst_edges])
# 使用DFS生成路径
path = list(nx.dfs_preorder_nodes(mst_graph, source=0))
path.append(path[0]) # 回到起点
return path
# 使用贪心算法
print("\n贪心算法构建初始解:")
greedy_path = greedy_initial_solution(G)
greedy_distance = calculate_total_distance(G, greedy_path)
city_names_greedy = [cities[i] for i in greedy_path]
print(f"路径: {' -> '.join(city_names_greedy)}")
print(f"总距离: {greedy_distance:.1f} 公里")
# 对贪心解进行2-opt优化
improved_greedy_path = two_opt_improvement(G, greedy_path)
improved_greedy_distance = calculate_total_distance(G, improved_greedy_path)
city_names_improved = [cities[i] for i in improved_greedy_path]
print(f"\n优化后路径: {' -> '.join(city_names_improved)}")
print(f"优化后距离: {improved_greedy_distance:.1f} 公里")
print(f"优化比例: {(1 - improved_greedy_distance/greedy_distance)*100:.1f}%")
性能对比与分析
import time
def benchmark_tsp_methods(G):
"""对比不同TSP方法的性能"""
methods = {
'暴力求解': brute_force_tsp,
'最近邻算法': lambda g: nearest_neighbor_tsp(g, 0),
'贪心+MST': greedy_initial_solution,
'最近邻+2opt': lambda g: two_opt_improvement(g, nearest_neighbor_tsp(g, 0)[0])
}
results = []
for name, method in methods.items():
start_time = time.time()
try:
if name == '暴力求解':
path, distance = method(G)
elif name == '贪心+MST':
path = method(G)
distance = calculate_total_distance(G, path)
else:
path, distance = method(G)
elapsed_time = time.time() - start_time
results.append({
'方法': name,
'路径长度': distance,
'执行时间': elapsed_time
})
print(f"{name}: 距离={distance:.1f}km, 时间={elapsed_time:.4f}s")
except Exception as e:
print(f"{name}: 执行失败 - {str(e)}")
return results
# 执行性能对比
print("\n性能对比:")
if len(cities) <= 8:
results = benchmark_tsp_methods(G)
else:
print("城市数量过多,跳过暴力求解")
methods = {
'最近邻算法': lambda g: nearest_neighbor_tsp(g, 0),
'贪心+MST': greedy_initial_solution,
'最近邻+2opt': lambda g: two_opt_improvement(g, nearest_neighbor_tsp(g, 0)[0])
}
核心要点
- 暴力求解:适合小规模(≤8个城市),保证最优解
- 最近邻算法:简单高效,但可能陷入局部最优
- 2-opt优化:显著改善路径质量,实用性强
- 贪心算法:利用MST构建初始解,质量较好
- 性能考虑:实际应用通常结合多种算法
这个案例展示了如何利用NetworkX构建图模型,并通过不同算法解决TSP问题。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播