局部搜索算法(Local Search)求解TSP问题 python实现

本文介绍了局部搜索算法在旅行商问题中的应用,通过定义邻域(如交换路径中城市访问顺序)并用Python实现,展示了如何通过k-opt策略进行优化。同时提到了禁忌搜索、模拟退火和变邻域搜索等启发式算法作为局部搜索的改进方法。
摘要由CSDN通过智能技术生成

局部搜索概念

wikipedia:
局部搜索算法从一个候选解开始,反复探索其邻域,并移动到邻域中的最后解。所以要使用局部搜索算法必须首先在搜索空间中定义邻域。比如,在最小顶点覆盖问题中,一个覆盖的邻域可以是只改变一个顶点能够到达的另一种覆盖;在布尔可满足性问题中,一个变量赋值的邻域可以是只改变一个变量的值能到达的所有赋值。对于同一个问题可以有很多种邻域的定义。如果一个局部优化算法将邻域定义为只改变 k 个成分能够到达的解,那么这个算法可以称为 k-opt

定义邻域

我们简单定义一个邻域,即随机交换路径中的两个城市的访问顺序,如下图所示:
image.png
反复迭代,直到达到设定的迭代次数

编码

我们使用python来实现这个简单的方法

计算距离矩阵

  • 导入tsp文件
filepath = './china34.tsp'
with open(filepath, 'r') as file:
    lines = file.readlines()

nodes = []

for i in range(len(lines)):
    if i < 6:
        continue
    info = lines[i].split()
    if info[0] == 'EOF':
        break
    coor = [float(info[1]), float(info[2])]
    nodes.append(coor)
  • 计算距离矩阵
D = np.radians(nodes)

city_cnt = len(nodes)
dist_mat = np.zeros((city_cnt, city_cnt))

for i in range(city_cnt):
    for j in range(city_cnt):
        if i == j:
            # 相同城市不允许访问
            dist_mat[i][j] = 0  # 修改为0表示同一个城市的距离为0
        else:
            # 使用 Haversine 公式计算距离
            lat1, lon1 = D[i][1], D[i][0]
            lat2, lon2 = D[j][1], D[j][0]

            # Haversine 公式
            dlat = lat2 - lat1
            dlon = lon2 - lon1
            a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
            c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
            distance = 6378.14 * c  # 6378.14 是地球的半径,单位:km

            dist_mat[i][j] = distance
  • tsp文件
NAME: china34
TYPE: TSP
COMMENT: 34 locations in China
DIMENSION: 34
EDGE_WEIGHT_TYPE: WGS
NODE_COORD_SECTION
1 101.74 36.56
2 103.73 36.03
3 106.27 38.47
4 108.95 34.27
5 113.65 34.76
6 117.00 36.65
7 114.48 38.03
8 112.53 37.87
9 111.65 40.82
10 116.41 39.90
11 117.20 39.08
12 123.38 41.80
13 125.35 43.88
14 126.63 45.75
15 121.47 31.23
16 120.19 30.26
17 118.78 32.04
18 117.27 31.86
19 114.31 30.52
20 113.00 28.21
21 115.89 28.68
22 119.30 26.08
23 121.30 25.03
24 114.17 22.32
25 113.55 22.20
26 113.23 23.16
27 110.35 20.02
28 108.33 22.84
29 106.71 26.57
30 106.55 29.56
31 104.06 30.67
32 102.73 25.04
33 91.11 29.97
34 87.68 43.77
EOF

定义邻域方法

def two_swap(path):
    cp = copy.deepcopy(path)
    r = random.sample(list(range(len(cp))), 2)
    cp[r[0]], cp[r[1]] = cp[r[1]], cp[r[0]]
    return cp

邻域搜索

def local_search():
    iterations = 10000
    path0 = list(range(len(dist_mat)))
    best = calcTSP(path0)
    for i in range(iterations):
        newpath = two_swap(path0)
        if calcTSP(newpath) < best:
            path0 = newpath
            best = calcTSP(newpath)
    print("best value:",best)
    print("best path:", path0)

完整代码

import copy

import pandas as pd
import numpy as np
import math
import random

filepath = './china34.tsp'
with open(filepath, 'r') as file:
    lines = file.readlines()

nodes = []

for i in range(len(lines)):
    if i < 6:
        continue
    info = lines[i].split()
    if info[0] == 'EOF':
        break
    coor = [float(info[1]), float(info[2])]
    nodes.append(coor)


D = np.radians(nodes)

city_cnt = len(nodes)
dist_mat = np.zeros((city_cnt, city_cnt))

for i in range(city_cnt):
    for j in range(city_cnt):
        if i == j:
            # 相同城市不允许访问
            dist_mat[i][j] = 0  # 修改为0表示同一个城市的距离为0
        else:
            # 使用 Haversine 公式计算距离
            lat1, lon1 = D[i][1], D[i][0]
            lat2, lon2 = D[j][1], D[j][0]

            # Haversine 公式
            dlat = lat2 - lat1
            dlon = lon2 - lon1
            a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
            c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
            distance = 6378.14 * c  # 6378.14 是地球的半径,单位:km

            dist_mat[i][j] = distance

def local_search():
    iterations = 10000
    path0 = list(range(len(dist_mat)))
    best = calcTSP(path0)
    for i in range(iterations):
        newpath = two_swap(path0)
        if calcTSP(newpath) < best:
            path0 = newpath
            best = calcTSP(newpath)
    print("best value:",best)
    print("best path:", path0)

def two_swap(path):
    cp = copy.deepcopy(path)
    r = random.sample(list(range(len(cp))), 2)
    cp[r[0]], cp[r[1]] = cp[r[1]], cp[r[0]]
    return cp

def calcTSP(path):
    sum = 0
    for i in range(1, len(path)):
        sum += dist_mat[path[i]][path[i-1]]
    sum += dist_mat[path[0]][path[len(path)-1]]
    return sum

local_search()

总结

简单的局部搜索会陷入局部最优,因此很多启发式算法针对局部搜索进行了优化,包括禁忌搜索(Tabu Search),模拟退火(SA),变邻域搜索(VNS),后面会针对这些方法做简单的介绍,并编码对比它们的效果。

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
遗传算法是一种启发式优化算法,常用于求解TSP(Traveling Salesman Problem)问题。下面是使用遗传算法求解TSP问题Python代码示例: ```python import random # 定义TSP问题的距离矩阵 distance_matrix = [ [0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0] ] # 定义遗传算法的参数 population_size = 50 # 种群大小 elite_size = 10 # 精英个体数量 mutation_rate = 0.01 # 变异率 generations = 100 # 迭代次数 # 创建一个个体(路径) def create_individual(): individual = list(range(len(distance_matrix))) random.shuffle(individual) return individual # 创建初始种群 def create_population(): population = [] for _ in range(population_size): population.append(create_individual()) return population # 计算路径的总距离 def calculate_fitness(individual): total_distance = 0 for i in range(len(individual)): from_city = individual[i] to_city = individual[(i + 1) % len(individual)] total_distance += distance_matrix[from_city][to_city] return total_distance # 选择精英个体 def select_elite(population): population_with_fitness = [(individual, calculate_fitness(individual)) for individual in population] population_with_fitness.sort(key=lambda x: x[1]) return [individual for individual, _ in population_with_fitness[:elite_size]] # 交叉互换操作 def crossover(parent1, parent2): child = [None] * len(parent1) start_index = random.randint(0, len(parent1) - 1) end_index = random.randint(start_index + 1, len(parent1)) child[start_index:end_index] = parent1[start_index:end_index] for i in range(len(parent2)): if parent2[i] not in child: for j in range(len(child)): if child[j] is None: child[j] = parent2[i] break return child # 变异操作 def mutate(individual): for i in range(len(individual)): if random.random() < mutation_rate: j = random.randint(0, len(individual) - 1) individual[i], individual[j] = individual[j], individual[i] return individual # 进化过程 def evolve(population): elite = select_elite(population) new_population = elite[:] while len(new_population) < population_size: parent1 = random.choice(elite) parent2 = random.choice(elite) child = crossover(parent1, parent2) child = mutate(child) new_population.append(child) return new_population # 主函数 def tsp_ga(): population = create_population() for _ in range(generations): population = evolve(population) best_individual = min(population, key=calculate_fitness) best_distance = calculate_fitness(best_individual) return best_individual, best_distance # 执行遗传算法求解TSP问题 best_individual, best_distance = tsp_ga() print("Best individual:", best_individual) print("Best distance:", best_distance) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值