1. 程式人生 > >2-opt求解TSP(旅行商)問題的python實現

2-opt求解TSP(旅行商)問題的python實現

2-opt其實是2-optimization的縮寫,簡言之就是兩元素優化。也可以稱作2-exchange 。(摘自百度百科)

這個一種隨機性演算法,基本思想就是隨機取兩個元素進行優化,一直到無法優化為止。在小規模TSP問題上,2-opt無論從效率還是效果上都優於蟻群演算法。

最初這個演算法就是在解決TSP問題上取得了比較好的成效,這裡也以TSP問題為例。

TSP(旅行商)問題:假設有十一座城市,一位旅行商要經過這十一座城市並且最終返回出發的城市,求解最短的路線。

使用2-opt思想解決該問題的演算法如下(首先設定引數最大迭代次數maxCount,初始化計數器count為0):

  1. 隨機選擇一條路線(比方說是A->B->C->D->E->F->G),假設是最短路線min;
  2. 隨機選擇在路線s中不相連兩個節點,將兩個節點之間的路徑翻轉過來獲得新路徑,比方我們隨機選中了B節點和E節點,則新路徑為A->(E->D->C->B)->F->G,()部分為被翻轉的路徑;
  3. 如果新路徑比min路徑短,則設新路徑為最短路徑min,將計數器count置為0,返回步驟2,否則將計數器count加1,當count大於等於maxCount時,演算法結束,此時min即為最短路徑,否則返回步驟2;

在網上沒能找到相關的python程式碼實現,於是我就自己粗糙地實現了一個(資料來源於某次華為杯數學建模競賽):

# -*- coding: utf-8 -*-
"""
Created on Fri Jul 21 13:47:57 2017

@author: 燃燒杯
"""
import numpy as np import matplotlib.pyplot as plt #在這裡設定迭代停止條件,要多嘗試一些不同數值,最好設定大一點 MAXCOUNT = 100 #資料在這裡輸入,依次鍵入每個城市的座標 cities = np.array([ [256, 121], [264, 715], [225, 605], [168, 538], [210, 455], [120, 400], [96, 304], [10,451], [
162, 660], [110, 561], [105, 473] ]) def calDist(xindex, yindex): return (np.sum(np.power(cities[xindex] - cities[yindex], 2))) ** 0.5 def calPathDist(indexList): sum = 0.0 for i in range(1, len(indexList)): sum += calDist(indexList[i], indexList[i - 1]) return sum #path1長度比path2短則返回true def pathCompare(path1, path2): if calPathDist(path1) <= calPathDist(path2): return True return False def generateRandomPath(bestPath): a = np.random.randint(len(bestPath)) while True: b = np.random.randint(len(bestPath)) if np.abs(a - b) > 1: break if a > b: return b, a, bestPath[b:a+1] else: return a, b, bestPath[a:b+1] def reversePath(path): rePath = path.copy() rePath[1:-1] = rePath[-2:0:-1] return rePath def updateBestPath(bestPath): count = 0 while count < MAXCOUNT: print(calPathDist(bestPath)) print(bestPath.tolist()) start, end, path = generateRandomPath(bestPath) rePath = reversePath(path) if pathCompare(path, rePath): count += 1 continue else: count = 0 bestPath[start:end+1] = rePath return bestPath def draw(bestPath): ax = plt.subplot(111, aspect='equal') ax.plot(cities[:, 0], cities[:, 1], 'x', color='blue') for i,city in enumerate(cities): ax.text(city[0], city[1], str(i)) ax.plot(cities[bestPath, 0], cities[bestPath, 1], color='red') plt.show() def opt2(): #隨便選擇一條可行路徑 bestPath = np.arange(0, len(cities)) bestPath = np.append(bestPath, 0) bestPath = updateBestPath(bestPath) draw(bestPath) opt2()

執行結果(只取了最後兩行輸出):

1511.49908777
[0, 4, 3, 2, 1, 8, 9, 10, 7, 5, 6, 0]

執行結果

注:因為該演算法具有隨機性,所以每次執行的結果可能都有所不同,但是大多都是在1500~1600之內,要多執行幾次比較一下取較好的結果,我上面給的執行結果就是我在幾次執行中挑選得比較好的一次

關於調參:
本演算法只有COUNTMAX一個引數,用於設定演算法的停止條件,當演算法已經連續COUNTMAX次沒能得到更好的路徑時便會停止,經過試驗,一般設定大一些效果會比較好,但是大到一定程度的情況下再增大數值演算法的效果也不會變得更好。