轉載自:wangqiuyun
原文連結:http://blog.csdn.net/wangqiuyun/article/details/12838903
一、TSP問題
TSP問題(Travelling Salesman Problem)即旅行商問題,又譯為旅行推銷員問題、貨郎擔問題,是數學領域中著名問題之一。假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最後要回到原來出發的城市。路徑的選擇目標是要求得的路徑路程為所有路徑之中的最小值。
TSP問題是一個組合最佳化問題。該問題可以被證明具有NPC計算複雜性。TSP問題可以分為兩類,一類是對稱TSP問題(Symmetric TSP),另一類是非對稱問題(Asymmetric TSP)。所有的TSP問題都可以用一個圖(Graph)來描述:
V={c1, c2, …, ci, …, cn},i = 1,2, …, n,是所有城市的集合.ci表示第i個城市,n為城市的數目;
E={(r, s): r,s∈ V}是所有城市之間串連的集合;
C = {crs: r,s∈ V}是所有城市之間串連的成本度量(一般為城市之間的距離);
如果crs = csr, 那麼該TSP問題為對稱的,否則為非對稱的。
一個TSP問題可以表達為:
求解遍曆圖G = (V, E, C),所有的節點一次並且回到起始節點,使得串連這些節點的路徑成本最低。
二、遺傳演算法
遺傳演算法(Genetic Algorithms )是基於生物進化理論的原理髮展起來的一種廣為應用的、高效的隨機搜尋與最佳化的方法。其主要特點是群體搜尋策略和群體中個體之間的資訊交換,搜尋不依賴於梯度資訊。它是在70年代初期由美國密西根( Michigan )大學的霍蘭( Holland )教授發展起來的。1975年霍蘭教授發表了第一本比較系統論述遺傳演算法的專著《自然系統與人工系統中的適應性》(《 Adaptationin Natural and Artificial Systems 》)。遺傳演算法最初被研究的出發點不是為專門解決最佳化問題而設計的,它與進化策略、進化規劃共同構成了進化演算法的主要架構,都是為當時人工智慧的發展服務的。迄今為止,遺傳演算法是進化演算法中最廣為人知的演算法。
遺傳火演算法的實施步驟如下(以目標函數求最小為例)。
第一步:初始化 t←0進化代數計數器;T是最大進化代數;隨機產生M個個體作為初始群體P(t);
第二步:個體評價 計算P(t)中各個個體的適應度;
第三步:選擇運算 將選擇運算元作用於群體;
第四步:交叉運算 將交叉運算元作用於群體;
第五步:變異運算 將變異運算元作用於群體,並通過以上運算得到下一代群體P(t + 1);
第六步:終止條件判斷 t≦T:t← t+1 轉到步驟2;t>T:終止 輸出解。
遺傳演算法應用步驟:
1)確定決策變數及各種約束條件,即個體的表現型X和問題的解空間;
2)建立最佳化模型 (目標函數最大OR 最小) 數學描述形式 量化方法;
3)染色體編碼方法;
4)解碼方法;
5)個體適應度的量化評價方法 F(x)
6)設計遺傳運算元;
7)確定有關運行參數。
三、遺傳演算法求解TSP問題
其實之前不大想寫這個遺傳演算法求TSP,因為我之前已經有遺傳演算法求01背包了,但有些讀者建議,加上確實tsp與01背包差別還是很大的,就再寫一個。對於TSP之類的問題NP問題,使用啟發學習法搜尋演算法是一個明智的選擇,因為精確算髮已經力不從心了。
使用遺傳演算法第一件事情就是確定染色編碼方式,它根據不同的問題模型使用不同編碼方式,有二進位編碼也有整數編碼和浮點數編碼,面對TSP問題,我肯定選用整數編碼,因為很簡單,對於每個城市用一個整數來編號,例如有48個城市,就用0到47來標識每一個城市,然後一個路徑就是一條染色體編碼,染色體長度為48,如:0,1,2,3,4...47就是一個染色體,它表達的意思就是旅行者從0號城市出發,依次訪問1,2,...47號城市再回到0號城市;遺傳演算法的第二個要點就是評價函數,TSP的評價函數很簡單,就是染色體編碼錶達的路徑總長度;最後很簡單,其實在這個模型中就是將0到47這48個數進行全排列,從中找出最短的一條路徑(想想48個數全排列,然後比較。。。)。清楚瞭解了這些,咱們就可以按照上面的遺傳演算法架構來進行編程了。
我們使用TSP問題依然來自於tsplib上的資料att48,這是一個對稱TSP問題,城市規模為48,其最優值為10628.其距離計算方法下圖所示:
具體代碼如下: [java] view plain copy package noah; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Random; public class GA { private int scale;// 種群規模 private int cityNum; // 城市數量,染色體長度 private int MAX_GEN; // 運行代數 private int[][] distance; // 距離矩陣 private int bestT;// 最佳出現代數 private int bestLength; // 最佳長度 private int[] bestTour; // 最佳路徑 // 初始種群,父代種群,行數表示種群規模,一行代表一個個體,即染色體,列表示染色體基因片段 private int[][] oldPopulation; private int[][] newPopulation;// 新的種群,子代種群