1. 程式人生 > >用Python解決TSP問題(2)——動態規劃演算法

用Python解決TSP問題(2)——動態規劃演算法

本介紹用python解決TSP問題的第二個方法——動態規劃法

演算法介紹

動態規劃演算法根據的原理是,可以將原問題細分為規模更小的子問題,並且原問題的最優解中包含了子問題的最優解。也就是說,動態規劃是一種將問題例項分解為更小的、相似的子問題,並存儲子問題的解而避免計算重複的子問題,以解決最優化問題的演算法策略。

我使用DP求解TSP問題的主要分為三個主要部分:

1)     假定我們從城市0出發,經過了所有城市,並返回到城市0。那麼我們需要記錄的資訊有:當前所在城市location,當前未遍歷的城市集合s。

2)     狀態轉移方程,狀態轉移方程是DP演算法的核心部分,它代表了子問題和原問題的關係,通過狀態轉移方程可以將原問題不斷細分為各個子問題。我們狀態轉移方程的定義如下所示:

T(s,init)代表的意思是從init點出發經過s中全部的點回到init的距離。

3)     構建T表記錄T的值,如果不去記錄每次遞迴的T值,那麼以後每次搜尋都要重新計算,就成了暴力搜尋。所以我們構建一個T表dp[s][init],記錄每次求出來的T函式值,即將T(s,init)的值記錄在dp[s][init]位置。

程式

輸入:

1 2066 2333
2 935 1304
3 1270 200
4 1389 700
5 984 2810
6 2253 478
7 949 3025
8 87 2483
9 3094 1883
10 2706 3130

程式碼:

"""
動態規劃法
name:xxx
date:6.8
"""
import pandas as pd
import numpy as np
import math
import time

dataframe = pd.read_csv("./data/TSP10cities.tsp",sep=" ",header=None)
v = dataframe.iloc[:,1:3]

train_v= np.array(v)
train_d=train_v
dist = np.zeros((train_v.shape[0],train_d.shape[0]))

#計算距離矩陣
for i in range(train_v.shape[0]):
    for j in range(train_d.shape[0]):
        dist[i,j] = math.sqrt(np.sum((train_v[i,:]-train_d[j,:])**2))

"""
N:城市數
s:二進位制表示,遍歷過得城市對應位為1,未遍歷為0
dp:動態規劃的距離陣列
dist:城市間距離矩陣
sumpath:目前的最小路徑總長度
Dtemp:當前最小距離
path:記錄下一個應該到達的城市
"""

N=train_v.shape[0]
path = np.ones((2**(N+1),N))
dp = np.ones((2**(train_v.shape[0]+1),train_d.shape[0]))*-1

def TSP(s,init,num):
    if dp[s][init] !=-1 :
        return dp[s][init]
    if s==(1<<(N)):
        return dist[0][init]
    sumpath=1000000000
    for i in range(N):
        if s&(1<<i):
            m=TSP(s&(~(1<<i)),i,num+1)+dist[i][init]
            if m<sumpath:
                sumpath=m
                path[s][init]=i
    dp[s][init]=sumpath
    return dp[s][init]

if __name__ == "__main__":
    init_point=0
    s=0
    for i in range(1,N+1):
        s=s|(1<<i)
    start = time.clock()
    distance=TSP(s,init_point,0)
    end = time.clock()
    s=0b11111111110
    init=0
    num=0
    print(distance)
    while True:
        print(path[s][init])
        init=int(path[s][init])
        s=s&(~(1<<init))
        num+=1
        if num>9:
            break
    print("程式的執行時間是:%s"%(end-start))

結果: