递推与储存,是动态规划的关键
小智最近由于項目需要,經常要接觸到一些規劃類的問題。那今天就給大家講一講旅行商問題及其解法吧。
旅行商問題,即TSP問題(Travelling Salesman Problem)。問題是,有一個旅行商人要拜訪n個城市,每個城市只能拜訪一次,而且最后要回到原來出發的城市。這位商人如何設計拜訪順序,使走過的路徑最短??
這種求最短距離問題有非常多實際場景會涉及到,比如,快遞公司為了使城市A到城市B的快遞件運輸速度達到最快,他們會選擇城市A到城市B的最短路徑來進行運輸。再比如,游戲當中的角色移動時,需要尋找到一條最短路徑進行移動,這樣游戲中的角色才不會失真。又比如,網絡當中需要有路由算法,用于計算最短的信息跳轉路徑。
一款RPG游戲的角色移動演示,你會發現角色走路沿最短路徑。如果不這樣設計,游戲的體驗感則會非常糟糕
這么多實際的精彩案例,旅行商問題確實值得研究,而且學習完說不定能派上用場。
對于這類問題,我個人這次傾向使用動態規劃算法來解這道問題,得到他的精確解。
動態規劃這種技術也是有非常多實際場景會涉及到,比如,以動態規劃為基礎原理的維特比算法,現今常用于語音識別這個領域。再比如,生物信息學中需要進行DNA之間的比對,找出最長的公共DNA部分。
語音識別技術使得人機交互的難度不斷下降,其背后離不開數學
這里首先講解一下動態規劃的步驟:
1、分段:將原問題分解為若干個相互重疊的子問題。
2、分析:分析問題,找出遞推式。
3、求解:利用遞推式自底向上計算,實現動態規劃過程。
其實,動態規劃的精妙之處在于,每個子問題只求解一次,并將解保存在一個表格中,當需要再次求解此子問題時,只是簡單地通過查表獲得該子問題的解,避免大量的重復計算。
為了更好地在旅行商問題上講解動態規劃算法,這里講一個簡單的例子,隔壁村的老王要去這4座城市拜訪,城市之間的距離如下圖。
四座城市之間的距離示意圖
圖中一共有4座城市,城市0、城市1、城市2、城市3。小智目測走完這幾個城市的最短路程為10(城市0→城市1→城市2→城市3→城市0)。
人總是有直覺,而且有時會非常準。
當然,我們要用科學而完整的方法而得到最短的拜訪路徑,不能總是依賴直覺,盡管直覺經常是對的。我們先用窮舉法列一下所有路徑:
這是暴力的窮舉法,一共需要運算3!×4=24次加法。
暴力法是能得到結果,但是時間復雜度是階乘階O(n!),是算法當中復雜度極高的等級。
常見的算法時間復雜度由小到大依次為:
常數階Ο(1)<對數階Ο(logn)<線性階Ο(n)<線性對數階Ο(nlogn)<平方Ο(n^2)<立方階Ο(n^3)<…<指數階Ο(2^n)<階乘階Ο(n!)。
?
從動態規劃的角度看,假如我們找到一條最短的路徑:城市0→城市1→城市2→城市3→城市0
那么,城市1→城市2→城市3→城市0必然是城市1到城市0的一條最短路徑。
假設該路徑不是城市1到城市0的一條最短路徑,設該路徑的總路程為d,那么會有一條新的路徑作為城市1到城市0的最短路徑d’, d > d’,那么城市0→新路徑→城市0為完成拜訪的最短路徑,與原假設”找到一條最短路徑:城市0→城市1→城市2→城市3→城市0”矛盾。
按照上述結論,可以將路徑進行分解。設最短路徑的符號標記為?L。那么:
L(城市0→城市0) = L(城市0→城市1) + L(城市1到城市0)
請注意,城市0是起點城市和終點城市。
假如已經獲知各座城市到城市0的最短路徑,那么從城市0到城市0歸結起來一共有三種路徑:
L(城市0→城市1) + L(城市1到城市0)
L(城市0→城市2) + L(城市2到城市0)
L(城市0→城市3) + L(城市3到城市0)
在上述路徑找到最短的路徑,即為拜訪所有城市的最短路徑。
上述路徑可以繼續分解。比如,以第1條路徑為例:
L(城市1到城市0) = L(城市1→城市2) + L(城市2到城市0)
就這樣,路徑一直可以被分解,到什么時候結束呢?假設繼續以上述的L(城市1到城市0)為例,繼續對L(城市2到城市0)進行分解:
L(城市2到城市0) = L(城市2→城市3) + L(城市3到城市0)
由于城市1、城市2之前已經出現過了,因此L(城市3到城市0)只能等于L(城市3→城市0)
至此,城市間的路徑全部可以被分解。
我們以符號來表達上述的過程。假設?d(i, V)?表示從城市 i經過城市集合 V各點一次后返回到出發點的最短距離。d(i, V)?可以按照一下方式分解:
其中,Cki?為城市?k?到城市i?的距離。
這樣,動態規劃的遞推式出來了。
從城市0出發,經過城市1、2、3后回到城市0的最短路徑長度為:
這個是最后一個階段的決策,它必須依據?d(1, {2,3})、d(2, {1,3})?和?d(3, {1,2})的計算結果,繼續分解:
當然,還可以繼續進行分解:
上述過程可以發現,在計算的時候,可以不斷引用先前的計算結果,這就是動態規劃的特點。我們將上述過程在表格中把填寫一下:
至此,發現拜訪完所有城市的最短距離為10,印證了小智原來的想法。
上述執行加法的次數:
時間復雜度為O(2n)。動態規劃相比起窮舉法下降了一個等級,這個算法起到了重要的價值。
完成原理闡述,是時候寫代碼了,先整理一下偽代碼:
1、初始化一個表格d,用于記錄計算結果。并以距離初始化第0列
2、循環j=1:2n-1-1
循環 i=(1:n,且不包含在V[j])
? ? ? ? 循環 V[j]中的所有元素
? ? ? ? ?d[i][j] = min(c[i,k], d[k][V[j]去掉k元素后對應的序號])
3、計算d[0][2n-1-1] = min(c[0,k] +d[k][2n-1-2],此為最短路徑長度
這里需要注意的是,集合V是從小變大,要先算V較小的部分,因此要找一個方式來表達集合V,然后對計算進行順序。
這里將數字轉換為二進制序列,以表示集合V擁有的元素,比如:[1,0,0],可表示集合V只包含元素1,[0,1,1],可表示集合V包含元素2和元素3。
二進制數可以映射到自然數區,比如:
0 →[0,0,0]、1 → [1,0,0]、2 → [0,1,0]、3 → [1,1,0]
4 →[0,0,1]、5 → [1,0,1]、6 → [0,1,1]、7 → [1,1,1]
為了實現集合從小到大的計算順序,對二進制序列進行特別的排序,其中第一排序條件是序列的總和,升序。第二排序條件是序列代表的數字,升序,轉換為以下排序。
這樣,按照上述表格中的序號作為順序進行計算即可。
可以動手編程了。我們挑一道更難的題目,有10座城市的TSP問題:
另一道題目:10座城市之間的距離矩陣
有了想法很快就可以付諸實踐了(回復“TSP程序”可以獲得程序),這是最美妙的地方。按照上述流程,最短路徑距離為284,最短路線:
0→3→1→5→7→6→2→8→4→9→0
當然,這個并不是一個完美的解法,隨著城市數量的增加,計算難度呈指數增長,目前關于TSP在多項式時間內的解法目前還沒出現,但我相信未來一定會誕生。
總結
以上是生活随笔為你收集整理的递推与储存,是动态规划的关键的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文读懂 AVL 树
- 下一篇: “一边熬夜一边求不要猝死”,90后养生朋