1. 程式人生 > >用python來編寫TSP問題

用python來編寫TSP問題

import math
from os import path
import numpy as np
import matplotlib.pyplot as plt


class TSPInstance:
    '''
    設計一個類,實現從檔案讀入一個旅行商問題的例項
    檔案格式為:
    city number
    best known tour length
    list of city position (index x y)

    best known tour (city index starts from 1)

    以檔案01eil51.txt為例:
    第一行51為城市數
    第二行426為最優解的路徑長度
    第三行開始的51行為各個城市的序號、x座標和y座標
    最後是最優解的訪問城市系列(注意裡面城市序號從1開始,而python的sequence是從0開始)
    Eil51Tour.png是最優解的城市訪問順序圖
    '''

    def __init__(self, file_name):
        '''
        從檔案file_name讀入旅行商問題的資料
        '''
        self.file_name=file_name
        a= open(file_name)
        # 城市數量
        self.city_num = a.readline()
        # 返回座標 51行,3列
        self.city = np.zeros((int(self.city_num), 3))
        # x座標
        self.x = np.zeros(int(self.city_num))
        # y座標
        self.y = np.zeros(int(self.city_num))
        # 城市ID
        self.id = np.zeros(int(self.city_num))
        b = a.readlines()
        for i, content in enumerate(b):
                if i in range(1, 52 ):
                    # 單行賦值
                    self.city[i-1] = content.strip('\n').split(' ')
                    self.x[i-1] = self.city[i-1][1]
                    self.y[i-1] = self.city[i-1][2]
        for i, content in enumerate(b):
                if i in range(53, 104):
                    self.id[i - 53] = content.strip('\n')
    @property
    def citynum(self):
        '''
        返回城市數
        '''
        return self.city_num

    @property
    def optimalval(self):
        '''
        返回最優路徑長度
        '''
        c = 0
        i = 1
        s = open(self.file_name)
        str = s.readlines()
        for content in str:
            if i == 2:
                c = content
            i = i + 1
        return c

    @property
    def optimaltour(self):
        '''
        返回最優路徑
        '''
        tour = np.array(self.id)
        return tour

    def __getitem__(self, n):
        '''
        返回城市n的座標,由x和y構成的tuple:(x,y)
        '''
        (x, y) = (self.x[n-1], self.y[n-1])
        return (x, y)

    def get_distance(self, n, m):
        '''
        返回城市n、m間的整數距離(四捨五入)
        '''
        u=int(self.x[n-1] - self.x[m-1])
        v=int(self.y[n-1] - self.y[m-1])
        dis = math.sqrt(pow(u,2) + pow(v,2))
        return int(dis+0.5)

    def evaluate(self, tour):
        '''
        返回訪問系列tour所對應的路徑程度
        '''
        dis = 0
        for i in range(50):
            dis += self.get_distance(int(tour[i]), int(tour[i + 1]))
        dis += self.get_distance(int(tour[50]), int(tour[0]))
        return dis

    def plot_tour(self, tour):
        '''
        畫出訪問系列tour所對應的路徑路
        '''
        for i in range(51):
            x0,y0 = self.__getitem__(i)
            plt.scatter(int(x0),int(y0),s=10,c='c')
        #記住座標點的畫法
        for i in range(len(tour)-1):
            x1,y1 = self.__getitem__(int(tour[i]))
            x,y = self.__getitem__(int(tour[i+1]))
            plt.plot([x1,x],[y1,y],c='b')
        x2,y2 = self.__getitem__(int(tour[0]))
        x3,y3 = self.__getitem__(int(tour[len(tour)-1]))

        plt.plot([x2,x3],[y2,y3],c='b')
        plt.xlabel('x label')
        plt.ylabel('y label')
        plt.title("City access sequence diagram")
        plt.plot()
        plt.show()

if __name__ == "__main__":
    file_name = path.dirname(__file__) + "/1.txt"
    instance = TSPInstance(file_name)
    print(instance.citynum)
    print(instance.evaluate(instance.optimaltour))
    print(instance.optimaltour)
    print(instance.__getitem__(2))
    print(instance.get_distance(0, 1))
    instance.plot_tour(instance.optimaltour)
    '''
    output:
    51
    426
    [  1.  22.   8.  26.  31.  28.   3.  36.  35.  20.   2.  29.  21.  16.  50.
      34.  30.   9.  49.  10.  39.  33.  45.  15.  44.  42.  40.  19.  41.  13.
      25.  14.  24.  43.   7.  23.  48.   6.  27.  51.  46.  12.  47.  18.   4.
      17.  37.   5.  38.  11.  32.]
    (49.0, 49.0)
    14  
    '''

其實解決TSP問題有很多方法,比如模擬退火演算法,貪心演算法,回溯演算法等等。希望各位博友可以把你們的解決方法出現在評論區。