禁忌搜索算法(tabu search)及Python实现

本文介绍了禁忌搜索算法的概念,以及如何用Python实现该算法,包括随机初始路径、改良圈算法、贪心算法和禁忌表的应用,通过示例展示了算法在求解最优化问题上的过程和结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 一、禁忌搜索算法

        采用邻域选优的搜索方法,为了逃离局部最优解,算法必须能够接受劣解,也就是每一次得到的解不一定优于原来的解。但是,一旦接受了劣解,算法迭代即可能陷入循环。为了避免循环,算法将最近接受的一些移动放在禁忌表中,在以后的迭代中加以禁止。即只有不再禁忌表中的较好解(可能比当前解差)才能接受作为下一代迭代的初始解。随着迭代的进行,禁忌表不断更新,经过一定的迭代次数后,最早进入禁忌表的移动就从禁忌表中解禁退出。

二、Python实现

import matplotlib.pyplot as plt
import random
import time


Fee_data = [[0,382,352,800,666],
            [382,0,892,158,235],
            [253,780,0,678,111],
            [862,123,768,0,255],
            [666,1080,123,255,0]]

city_count = len(Fee_data[0])   # 城市数
origin = 1  # 起点、终点城市
remain_cities = [i for  i in range(city_count)]
remain_cities.remove(origin)    # 迭代过程中变动的城市
remian_count = city_count - 1

def route_mile_cost(route):
    """
    :param route:运行路线
    """
    mile_cost = 0.0
    mile_cost += Fee_data[origin-1][route[0]-1]
    for i in range(remian_count-1):
        mile_cost += Fee_data[route[i]-1][route[i+1]-1]
    mile_cost += Fee_data[route[-1]-1][origin-1]
    return mile_cost

def random_initial_route(remain_cities):
    """
    随机生成初始路径
    """
    initial_route = remain_cities[:]
    random.shuffle(initial_route)
    mile_cost = route_mile_cost
    return initial_route,mile_cost

improve_count = 20     # 改良次数
def improve_circle(remain_cities):
    """
    改良圈算法生成初始路径
    """
    initial_route = remain_cities[:]
    random.shuffle(initial_route)
    cost0 = route_mile_cost(initial_route)
    route = [1] + initial_route + [1]
    label = list(i for i in range(1,len(remain_cities)))
    j = 0
    while j < improve_count:
        new_route = route[:]
        index0, index1 = random.sample(label,2)
        new_route[index0],new_route[index1] = new_route[index1],\
            new_route[index0]
        cost1 = route_mile_cost(new_route[1:-1])
        improve = cost1-cost0
        if improve < 0:
            route = new_route[:]
            cost0 = cost1
            j += 1
        else:
            continue
    initial_route = route[1:-1]
    return initial_route,cost0


def nearest_city(current_city,cand_cities):
    """
    找寻当前城市最近的城市
    """
    temp_min = float("inf")
    next_city = None
    for i in range(len(cand_cities)):
        distance = Fee_data[current_city-1][cand_cities[i]-1]
        if distance < temp_min:
            temp_min = distance
            next_city = cand_cities[i]
    return next_city,temp_min

def greedy_initial_route(remain_cities):
    """
    贪婪算法,每次寻找最近的城市
    """
    cand_cities = remain_cities[:]
    current_city = origin
    mile_cost = 0
    initial_route = []
    # print(cand_cities,"cand_cities")
    while len(cand_cities) > 0:
        # 找到最近的城市
        next_city,distance = nearest_city(current_city,cand_cities)
        mile_cost += distance
        # 将下一个城市放入路径列表中
        initial_route.append(next_city)
        # 更新当前城市
        current_city = next_city
        # 更新未定序城市
        cand_cities.remove(next_city)
    # 回到起点
    mile_cost += Fee_data[initial_route[-1]-1][0]
    return initial_route,mile_cost

candidate_routes_size = 5
tabu_size = 10
tabu_list = [] #禁忌表
def random_swap_2_city(route):
    new_route = route[:]
    swap_2_city = random.sample(route,2)
    index = [0]*2
    index[0] = route.index(swap_2_city[0])
    index[1] = route.index(swap_2_city[1])
    index = sorted(index)
    L = index[1] - index[0] + 1
    for j in range(L):
        new_route[index[0]+j] = route[index[1]-j]
    return new_route,sorted(swap_2_city)

def generate_new_route(route):
    """
    生成新路线
    """
    global tabu_list,best_so_far_cost,best_so_far_route
    global candidate_routes,tabu_size
    candidate_routes = []   # 路线候选集合
    candidate_mile_cost = []    # 候选集合路线对应的费用
    candidate_swap = [] # 交换元素
    while len(candidate_routes) < candidate_routes_size:
        cand_route,cand_swap = random_swap_2_city(route)
        print("*******************")
        if cand_swap not in candidate_swap:     # 此次生成新路线的过程中,没有被交换过
            candidate_routes.append(cand_route)
            candidate_swap.append(cand_swap)
            candidate_mile_cost.append(route_mile_cost(cand_route))
    min_mile_cost = min(candidate_mile_cost)
    i = candidate_mile_cost.index(min_mile_cost)
    print(i,"i")
    # 如果这次交换集的最优值比历史最优值要好,则更新历史最优值和最优路线
    if min_mile_cost < best_so_far_cost:
        print("88888888")
        best_so_far_cost = min_mile_cost
        best_so_far_route = candidate_routes[i]
        print(best_so_far_route,"best_so_far_route")
        print(new_route,"new_route")
        new_route = candidate_routes[i]
        if candidate_swap[i] in tabu_list:
            print("))))))))))))))))藐视法则")
            tabu_list.remove(candidate_swap[i])     # 藐视法则
        elif len(tabu_list) >= tabu_size:
            print("2222222222222222222222")
            tabu_list.remove(tabu_list[0])
        tabu_list.append(candidate_swap[i])
    else:
        print(":::::::::")
        # 此次交换集未找到更优的路径,则选择交换方式未在禁忌表中的次优
        K = candidate_routes_size
        stop_value = K - len(tabu_list) - 1
        while K > stop_value:
            print(candidate_routes,"candidate_routes")
            min_mile_cost = min(candidate_mile_cost)
            i = candidate_mile_cost.index(min_mile_cost)
            # 如果这次的交换集的最优值比历史最优值更好,则更新历史最优解和最优路线
            if min_mile_cost < best_so_far_cost:
                print("[[[[[[[[[[[]]]]]]]]]]]")
                best_so_far_cost = min_mile_cost
                best_so_far_route = candidate_routes[i]
                new_route = candidate_routes[i]
                if candidate_swap[i] in tabu_list:
                    print("3333333333333333333333")
                    tabu_list.remove(candidate_swap[i])     #藐视法则
                elif len(tabu_list) >= tabu_size:
                    print("444444444444444444444")
                    tabu_list.remove(tabu_list[0])
                tabu_list.append(candidate_swap[i])
                break
            else:
                print("line175-----------")
                # 此次交换集未找到更优路径,则选择交换方式未在禁忌表中的次优
                if candidate_swap[i] not in tabu_list:
                    tabu_list.append(candidate_swap[i])
                    new_route = candidate_routes[i]
                    if len(tabu_list) > tabu_size:
                        print("55555555555555555555")
                        tabu_list.remove(tabu_list[0])
                    break
                else:
                    print("66666666666666666666666666")
                    candidate_mile_cost.remove(min_mile_cost)
                    candidate_swap.remove(candidate_swap[i])
                    candidate_routes.remove(candidate_routes[i])
                    K -= 1
        print(new_route,"new==========")
    return new_route,best_so_far_cost

def tabu_search(remain_cities,iteration_count = 10):
    global tabu_list,best_so_far_cost,best_so_far_route
    # 贪婪算法生成初始解
    best_so_far_route,best_so_far_cost = greedy_initial_route(remain_cities)
    # 随机生成初始解
    # best_so_far_route,best_so_far_cost = random_initial_route(remain_cities)
    # 改良圈算法生成初始解
    # best_so_far_route,best_so_far_cost = improve_circle(remain_cities)
    print("*******初始解生成完成********")
    print(best_so_far_route,"初始解")
    print(best_so_far_cost,"初始费用")
    new_route = best_so_far_route[:]
    print(new_route,"new_route")
    # 生成邻域空间
    # j = 0
    record = [best_so_far_cost]
    for j in range(iteration_count):
        # print(j,"j")
        new_route = generate_new_route(new_route)
        record.append(best_so_far_cost)
        # j += 1
        print(record,"record")
    # 输出最后搜索结果
    final_route = [origin] + best_so_far_route + [origin]
    return final_route,best_so_far_cost,record

def main():
    time_start = time.time()
    N = 100 #迭代次数
    satisfactory_solution,mile_cost,record = tabu_search(remain_cities,N)
    time_end = time.time()
    print("time cost:",(time_end-time_start))
    print("优化成本:%d"%(int(mile_cost)))
    print("优化路径:\n",satisfactory_solution)
    # 绘制迭代过程图
    X = [i for i in range(N+1)]
    Y = record[:]
    plt.xlabel("迭代次数",fontproperties = "SimSun")
    plt.ylabel("路径费用",fontproperties = "SimSun")
    plt.title("禁忌搜索法")
    plt.plot(X,Y,"-")
    plt.show()

if __name__ == "__main__":
    main()
        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oyoli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值