用Maple求解旅行推銷員問題
題記:
在中國,就數學軟件使用者數目而言, Matlab 一直是占領著高地。這與 Matlab 優秀的數值計算和處理大數據的能力密不可分,還有一個關鍵原因就是中國用戶多,交流環境良好。尺有所長,寸有所短,對于數學軟件而言也是如此。比如就符號計算能力而言,Matlab顯得相對不足,這時候恐怕要推薦一下 Maple或者 Mathematica。在使用軟件的過程中,筆者發現很多人拿著一方的優勢去有意貶低另外一個軟件的不足,我認為大可不必,作為使用者不必拘泥,可以依據實際情況各取所需,為我所用。
本文就拋轉引玉,介紹下maple軟件通用的一些使用方法,以及使用Maple 求解旅行推銷員相關問。Maple 是1982年加拿大Waterloo大學開發的一個符號運算和數值計算軟件平臺。之后幾乎每年都進行發布新版本,目前最新的版本是2019年三月發布的Maple 2019。它在處理數學相關問題相當出色和專業。結合Maple軟件學習數學也會增加相應的樂趣。
首先這里針對Maple初學者可能遇到疑惑的點解釋一下:為什么有的命令輸入可以起作用,有的命令明明輸入了怎么也不起作用。
比如想畫一個各占1/3的餅狀圖。我們查到命令: PieChart([1, 2, 3])。輸入之,很不幸你將會看到原樣輸出。這是為什么?
原因分析: Maple將一些專業性較強的關聯緊密的函數命令集成到各種包里。如線性代數相關的 (典型的如求特征值,行列式) 就放到LinearAlgebra 包里,統計相關的就放在Statistics 包里。你使用內置命令之前需要查幫助文檔(輸入相關命令按F2)看看是不是在某個包里。上面說的函數PieChart 就在Statistics 包里。最直接的辦法是添加with( Statistics): 效果圖如下:

言歸正傳,圖是一類重要的數據結構,圖論是研究圖的一門學科。可以利用Maple進行圖論的研究。當然也有的人用其繪制精美的圖論里的圖。注意:Maple 里的圖不支持含重邊和環邊。
圖論相關的放在GraphTheory 和 SpecialGraphs 包里,分別有197和 79 個函數命令。 還有一個是networks 包,不過這個包已經停止更新和維護,屬于將被棄用的狀態。Maple之所以保留并可以使用,估計Maple開發者有戀舊的美好情懷。
旅行推銷員問題 (英語:travelling salesman problem, TSP)是這樣一個問題:給定一系列城市和每對城市之間的距離,求解訪問每一座城市一次并回到起始城市的最短回路。它是組合優化中的一個NP困難問題,在運籌學和理論計算機科學中非常重要。
一個判定問題(答案只有是或者否)屬于NP 當且僅當這個問題是非確定型多項式時間可計算的。若NP問題類任何一個問題均可在多項式時間內轉成問題A, 稱 問題A 是NP 困難問題。說句人話就是這個問題本身比較復雜,隨著問題規模越大,即使再強大的計算機也幾乎無法求解。這時候規模大時候往往尋求近似解。
旅行推銷員問題在圖論中的一個等價形式是:給定一個加權完全圖(頂點表示城市,邊表示道路,權重就會是道路的成本或距離), 求一權值最小的哈密爾頓回路。
下面舉一個現在看起來瘋狂的例子。
大學畢業生小張準備騎自行車進行畢業旅行,出發地武漢,到南京,成都,合肥,西安,四個城市旅游,最后回到武漢。模型假設我們將五個城市視為圖的5個定點,他們的直接距離是圖的權重。上面城市分別記為1,2,3,4,5.
首先我們可以利用Wolfram Mathematica 聯網功能一次性求出它們之間的距離。

我們利用上面的距離數據在 Maple 里通過下列方式構建下面的圖:
restart;
with(GraphTheory):
# 5個城市, 問題歸結于在一個完全賦權圖找一個最優Hamilton 圈.
distanceofcities:= Matrix(5, {(1, 2) = 459.149, (1, 3) = 977.647,
(1, 4) =319.501,(1,5)=649.843,(2,3)=1406.79,(2,4)=143.539,(2,5)=953.511,
(3,4)= 1264.16,(3,5)=604.452,(4,5)=827.082 }, fill = 0, shape = symmetric): # 定義賦權矩陣distanceofcities
travelcities:=Graph(distanceofcities): # 通過賦權矩陣構成的完全賦權無向圖travelcities
DrawGraph(travelcities,stylesheet= [vertexborder = false, vertexpadding = 15,edgecolor="blue", vertexcolor="Gold",
edgethickness=5], font=["Courier",10], size=[400,400]);
然后利用內置命令求解:
t:=time[real]():
TravelingSalesman(travelcities);s
'time'=time[real]()-t; #記錄運行時間
運行結果如下:
(*結果解讀如下:選擇路線為武漢->合肥->南京->西安->成都->武漢,總行程2998.65公里。運行時間是0.051秒。*)
如果此時我們將城市擴大到10個,并考慮有時候由于地理條件的諸多原因兩地往返的路選擇未必一樣。也就是往返選擇的路的距離未必一致,這時侯考慮的就是有向圖了。Maple 照樣可以處理。
n:=10:
A1:= Matrix(n, (i,j)->`if`(i=j,0,n*(n-i)^4+2*j+(n-i)^2+j^3));
# A1 賦權矩陣
G1:=Graph(A1):
t:=time[real]():
TravelingSalesman(G1);
'time'=time[real]()-t;
運行結果是
這時我們會發現內置命令為56.79300 秒,時間已經算多的了,有人會問我們有希望自己編寫的代碼比內置命令更節省時間嗎?很多情況的確是可以幸運地做到的。下面的方面是把每個路線方法(共 10!/2= 1814400 種)進行比較。從方法上感覺很笨。
n:=10:
P:=Iterator:-Permute([seq(2..n)]):
cmin:=infinity: ord:= <"none">:
for v in P do
f:=add(A1[v[k],v[k+1]],k=1..n-2) + A1[1,v[1]]+A1[v[n-1],1];
if f<cmin then cmin:=f; ord:=copy(v) fi;
od:
cmin;tour:=[1, entries(ord,'nolist',indexorder),1];
'time'=time[real]()-t;
HighlightTrail(G1, tour, red);
DrawGraph(G1, style = circle);
運行結果如下:

得到了相同的結果,但是令人驚訝的是時間卻是1.775秒,遠遠小于內置方法。 其中原因估計有二:第一我們沒有采用真正意義上的暴力計算,而是巧妙地采用所謂惰性計算方法-迭代,這里主要體現在:
P:=Iterator:-Permute([seq(2..n)]): 。
第二點,我們考察 Maple 里TravelingSalesman 函數幫助文檔用的什么算法,可以看到如下文字: The algorithm is a branch-and-bound algorithm using the Reduce bound (see Kreher and Stinson, 1999).
于是我們知道主要采用分支定界算法,這個方法有時候搞不好枝搞地很多,將會花費很多時間去剪枝,有時候反而不如直接比較的方法來的快。所以說我們也不能過度依賴內置函數去處理問題,而是依據實際情況進行合理的處理。
至于較大規模的旅行銷售員問題的近似計算,有興趣地找找相關文獻讀讀。
最后,如果大家有matlab/maple/mathematica相關算法問題,可以通過我們的微信公眾號聯系我們。
微信公眾號:320科技工作室。
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP




















