天天看點

實驗10 禁忌搜尋算法求解tsp問題

傳送門(所有的實驗都使用python實作)

實驗1 BP神經網絡實驗

實驗2 som網實驗

實驗3 hopfield實作八皇後問題

實驗4 模糊搜尋算法預測薄冰厚度

實驗5 遺傳算法求解tsp問題

實驗6 蟻群算法求解tsp問題

實驗7 粒子群優化算法求解tsp問題

實驗8 分布估計算法求解背包問題

實驗9 模拟退火算法求解背包問題

實驗10 禁忌搜尋算法求解tsp問題

一、實驗目的

了解并使用禁忌搜尋算法

二、實驗内容

實作基于禁忌搜尋算法的TSP問題求解

三、實驗環境

使用Python3.0 在 eclipse進行編輯

四、實驗步驟

1、輸入介紹:

    城市總數目為14,采用以下城市坐标,坐标取整數。

實驗10 禁忌搜尋算法求解tsp問題

參數說明:  tl初始禁忌長度   time 疊代次數, spe 特赦值

2、産生初始解:

    随機産生一個合法的初始解,第一個城市固定,後面的兩個城市交換。

3、目标函數:

    巡回路徑的城市間距離之和作為目标函數,函數值最小即為最優解。

4、禁忌對象與規則:

    禁忌對象為兩個城市的交換,同時設定特赦值,當出現最優解且禁忌長度小于特赦值時,則特赦該對象,接受新解。否則被禁忌的對象無法産生新解。

5、鄰域搜尋:

    除起點外,枚舉交換任意兩個城市交換後的解,選取領域中合法的最優解更新目前解。

6、更新全局最優解。

7、終止條件

    達到目标疊代次數則終止并輸出結果,否則繼續在目前解的鄰域搜尋。

運作截圖:

    随機産生路線  距離99.503

實驗10 禁忌搜尋算法求解tsp問題

初始禁忌長度10 特赦值 5 疊代次數20  距離:58.349

實驗10 禁忌搜尋算法求解tsp問題

初始禁忌長度10 特赦值 5 疊代次數40  距離:48.191

實驗10 禁忌搜尋算法求解tsp問題

初始禁忌長度10 特赦值 5 疊代次數80  距離:45.472

實驗10 禁忌搜尋算法求解tsp問題

五、總結

禁忌長度的設定會直接影響到算法的時間,禁忌長度設定過大雖然鄰域搜尋時間變短但是最終結果并非最優,禁忌長度設定過短雖然結果較優,但是耗費了較多時間,本次實驗中初始禁忌長度設定10為最佳。

此外特赦值的大小也會影響算法結果,若特赦值過大,會導緻結果陷入局部最優,一直在某個局部最優解附近循環,若特赦值過小,會導緻失去接受最優解的機會。本次實驗中特赦值取5為最佳。

python源碼

#coding:gbk
import random
import math
import matplotlib.pyplot as plt
global m,best,tl; #m 城市個數 best全局最優   tl初始禁忌長度  
global time,spe ;    #  time 疊代次數, spe特赦值 
best = 10000.0;     
m=14; tl = 8; spe= 5; time=100  
tabu = [[0]*(m) for i in range(m)]   #禁忌表
best_way=[0]*m;  now_way=[0]*m;    #best_way 最優解  now_way目前解
dis = [[0]*(m) for i in range(m)] # 兩點距離 
class no:                       #該類表示每個點的坐标
    def __init__(self,x,y):
        self.x=x;
        self.y=y;
p=[];
def draw(t):              #該函數用于描繪路線圖
    x=[0]*(m+1);y=[0]*(m+1);
    for i in range(m):
        x[i] =p[t[i]].x;
        y[i] =p[t[i]].y;
    x[m] =p[t[0]].x;
    y[m] =p[t[0]].y;
    plt.plot(x,y,color='r',marker='*' ); 
    plt.show();
def  mycol():                           #城市坐标輸入
        p.append(no( 16 , 96 ));
        p.append(no( 16 , 94 )); p.append(no( 20 , 92 )); p.append(no( 22 , 93 )); p.append(no( 25 , 97 )); p.append(no( 22 , 96 )); p.append(no( 20 , 97 ));
        p.append(no( 17 , 96 )); p.append(no( 16 , 97 )); p.append(no( 14 , 98 )); p.append(no( 17, 97 )); p.append(no( 21 , 95 )); p.append(no( 19 , 97 ));
        p.append(no( 20 , 94 )); 
def  get_dis(a,b):       #傳回a,b兩城市的距離
    return   math.sqrt((p[a].x-p[b].x) *(p[a].x-p[b].x) +(p[a].y-p[b].y) *(p[a].y-p[b].y));
def get_value(t):        #計算解t的路線長度
    ans = 0.0;
    for i in range(1,m):     
        ans += dis[t[i]][t[i-1]]
    ans += dis[t[0]][t[m-1]]
    return ans;
def cop(a,b):     #把b數組的值指派a數組
    for i in range(m):
        a[i]=b[i]
def rand(g):                 # 随機生成初始解
    vis = [0]*m
    for i in range(m):
        vis[i]=0;
    on= 0
    while on<m:
        te = random.randint(0,m-1);
        if(vis[te]==0):
            vis[te]=1;
            g[on]=te;
            on+=1;
def init():            #初始化函數
    global best
    for i in range(m):
        for j in range(m):
            tabu[i][j] = 0;       #初始化禁忌表           
            dis[i][j]=get_dis(i,j); #計算兩點距離
    rand(now_way)  #生成初始解作為目前解
    now = get_value(now_way);
    cop(best_way,now_way); best = now;     
def slove():    #疊代函數
    global best,now;
    temp = [0]*m;   #中間變量記錄交換結果
    a = 0;b=0; # 記錄交換城市下标
    ob_way =[0]*m; cop(ob_way,now_way);ob_value= get_value(now_way);  #暫存鄰域最優解
    for i in range(1,m):    #搜尋所有鄰域
        for j in range(1,m):
            if(i+j >= m): break;
            if(i==j): continue;
            cop(temp,now_way)
            temp[i],temp[i+j]=temp[i+j],temp[i];  #交換
            value = get_value(temp)
            if(value <= best and tabu[i][i+j] < spe):  #如果優于全局最優且禁忌長度小于特赦值 
                cop(best_way,temp); best = value; a = i;b=i+j; #更新全局最優且接受新解
                cop(ob_way,temp); ob_value = value;
            elif(tabu[i][i+j]==0 and value < ob_value):  #如果優于鄰域中的最優解則
                cop(ob_way,temp); ob_value = value; a = i;b=i+j; #接受新解
    
    cop(now_way,ob_way);  #更新目前解
    for i in range(m):                    # 更新禁忌表
        for j in range(m):
            if(tabu[i][j] > 0): tabu[i][j]-=1;      
    tabu[a][b]=tl;  #重置a,b兩個交換城市的禁忌值    
#*************************主函數*************************
        
mycol();            #資料輸入    
init();                 #資料初始化

for i in range(time):      #控制疊代次數
    slove();
print("路線總長度:",round(best,3));       #列印最優解距離保留三位小數
draw(best_way);                      #畫圖描繪路線
print("具體路線:",best_way);                     #列印路線,以序清單示