多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > ACO蟻群算法解決TSP旅行商問題

ACO蟻群算法解決TSP旅行商問題

來源:程序員人生   發(fā)布時(shí)間:2015-05-25 09:28:43 閱讀次數(shù):3639次

前言

蟻群算法也是1種利用了大自然規(guī)律的啟發(fā)式算法,與之前學(xué)習(xí)過的GA遺傳算法類似,遺傳算法是用了生物進(jìn)行理論,把更具適應(yīng)性的基因傳給下1代,最后就可以得到1個(gè)最優(yōu)解,常經(jīng)常使用來尋覓問題的最優(yōu)解。固然,本篇文章不會(huì)主講GA算法的,想要了解的同學(xué)可以查看,我的遺傳算法學(xué)習(xí)遺傳算法在走迷宮中的應(yīng)用。話題重新回到蟻群算法,蟻群算法是1個(gè)利用了螞蟻尋覓食品的原理。不知道小時(shí)候有無發(fā)現(xiàn),當(dāng)1個(gè)螞蟻發(fā)現(xiàn)了地上的食品,然后非常迅速的,就有其他的螞蟻集合過來,最后把食品抬回家,這里面其實(shí)有著非常多的道理的,在ACO中就用到了這個(gè)機(jī)理用于解決實(shí)際生活中的1些問題。

螞蟻找食品

首先我們要具體說說1個(gè)成心思的事情,就是螞蟻找食品的問題,理解了這個(gè)原理以后,對理解ACO算法就非常容易了。螞蟻?zhàn)鳛槟悄┬〉膭?dòng)物,在地上漫無目的的尋覓食品,起初都是沒有目標(biāo)的,他從螞蟻洞中走出,隨機(jī)的爬向各個(gè)方向,在這期間他會(huì)向外界播撒1種化學(xué)物資,姑且就叫做信息素,所以這里就能夠得到的1個(gè)條件,越多螞蟻?zhàn)哌^的路徑,信息素濃度就會(huì)越高,那末某條路徑信息素濃度高了,自然就會(huì)有越多的螞蟻感覺到了,就集聚集過來了。所以當(dāng)眾多螞蟻中的1個(gè)找到食品以后,他就會(huì)在走過的路徑中放出信息素濃度,因此就會(huì)有很多的螞蟻趕來了。類似下面的場景:


至于螞蟻是如何感知這個(gè)信息素,這個(gè)就得問生物學(xué)家了,我也沒做過研究。

算法介紹

OK,有了上面這個(gè)自然生活中的生物場景以后,我們再來切入文章主題來學(xué)習(xí)1下蟻群算法,百度百科中對應(yīng)蟻群算法是這么介紹的:蟻群算法是1種在圖中尋覓優(yōu)化路徑的機(jī)率型算法。他的靈感就是來自于螞蟻發(fā)現(xiàn)食品的行動(dòng)。蟻群算法是1種新的摹擬進(jìn)化優(yōu)化的算法,與遺傳算法有很多相似的地方。蟻群算法在比較早的時(shí)候成功解決了TSP旅行商的問題(在后面的例子中也會(huì)以這個(gè)例子)。要用算法去摹擬螞蟻的這類行動(dòng),關(guān)鍵在于信息素的在算法中的設(shè)計(jì),和路徑中信息素濃度越大的路徑,將會(huì)有更高的幾率被螞蟻所選擇到。

算法原理

要想實(shí)現(xiàn)上面的幾個(gè)摹擬行動(dòng),需要借助幾個(gè)公式,固然公式不是我自己定義的,主要有3個(gè),以下圖:


上圖中所出現(xiàn)的alpha,beita,p等數(shù)字都是控制因子,所以可沒必要理睬,Tij(n)的意思是在時(shí)間為n的時(shí)候,從城市i到城市j的路徑的信息素濃度。類似于nij的字母是城市i到城市j距離的倒數(shù)。就是下面這個(gè)公式。


所以所有的公式都是為第1個(gè)公式服務(wù)的,第1個(gè)公式的意思是指第k只螞蟻選擇從城市i到城市j的幾率,可以見得,這個(gè)受距離和信息素濃度的兩重影響,距離越遠(yuǎn),去此城市的幾率自然也低,所以nij會(huì)等于距離的倒數(shù),而且在算信息素濃度的時(shí)候,也斟酌到了信息素濃度衰減的問題,所以會(huì)在上次的濃度值上乘以1個(gè)衰減因子P。另外還要加上本輪搜索增加的信息素濃度(假設(shè)有螞蟻經(jīng)過此路徑的話),所以這幾個(gè)公式的整體設(shè)計(jì)思想還是非常棒的。

算法的代碼實(shí)現(xiàn)

由于本身我這里沒有甚么真實(shí)的測試數(shù)據(jù),就隨意自己構(gòu)造了1個(gè)簡單的數(shù)據(jù),輸入以下,分為城市名稱和城市之間的距離,用#符號做辨別標(biāo)識,大家應(yīng)當(dāng)可以看得懂吧

# CityName 1 2 3 4 # Distance 1 2 1 1 3 1.4 1 4 1 2 3 1 2 4 1 3 4 1

螞蟻類Ant.java:

package DataMining_ACO; import java.util.ArrayList; /** * 螞蟻類,進(jìn)行路徑搜索的載體 * * @author lyq * */ public class Ant implements Comparable<Ant> { // 螞蟻當(dāng)前所在城市 String currentPos; // 螞蟻遍歷完回到原點(diǎn)所用的總距離 Double sumDistance; // 城市間的信息素濃度矩陣,隨著時(shí)間的增多而減少 double[][] pheromoneMatrix; // 螞蟻已走過的城市集合 ArrayList<String> visitedCitys; // 還未走過的城市集合 ArrayList<String> nonVisitedCitys; // 螞蟻當(dāng)前走過的路徑 ArrayList<String> currentPath; public Ant(double[][] pheromoneMatrix, ArrayList<String> nonVisitedCitys) { this.pheromoneMatrix = pheromoneMatrix; this.nonVisitedCitys = nonVisitedCitys; this.visitedCitys = new ArrayList<>(); this.currentPath = new ArrayList<>(); } /** * 計(jì)算路徑的總本錢(距離) * * @return */ public double calSumDistance() { sumDistance = 0.0; String lastCity; String currentCity; for (int i = 0; i < currentPath.size() - 1; i++) { lastCity = currentPath.get(i); currentCity = currentPath.get(i + 1); // 通過距離矩陣進(jìn)行計(jì)算 sumDistance += ACOTool.disMatrix[Integer.parseInt(lastCity)][Integer .parseInt(currentCity)]; } return sumDistance; } /** * 螞蟻選擇前往下1個(gè)城市 * * @param city * 所選的城市 */ public void goToNextCity(String city) { this.currentPath.add(city); this.currentPos = city; this.nonVisitedCitys.remove(city); this.visitedCitys.add(city); } /** * 判斷螞蟻是不是已又重新回到出發(fā)點(diǎn) * * @return */ public boolean isBack() { boolean isBack = false; String startPos; String endPos; if (currentPath.size() == 0) { return isBack; } startPos = currentPath.get(0); endPos = currentPath.get(currentPath.size() - 1); if (currentPath.size() > 1 && startPos.equals(endPos)) { isBack = true; } return isBack; } /** * 判斷螞蟻在本次的走過的路徑中是不是包括從城市i到城市j * * @param cityI * 城市I * @param cityJ * 城市J * @return */ public boolean pathContained(String cityI, String cityJ) { String lastCity; String currentCity; boolean isContained = false; for (int i = 0; i < currentPath.size() - 1; i++) { lastCity = currentPath.get(i); currentCity = currentPath.get(i + 1); // 如果某1段路徑的始末位置1致,則認(rèn)為有經(jīng)過此城市 if ((lastCity.equals(cityI) && currentCity.equals(cityJ)) || (lastCity.equals(cityJ) && currentCity.equals(cityI))) { isContained = true; break; } } return isContained; } @Override public int compareTo(Ant o) { // TODO Auto-generated method stub return this.sumDistance.compareTo(o.sumDistance); } }

蟻群算法工具類ACOTool.java:
package DataMining_ACO; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * 蟻群算法工具類 * * @author lyq * */ public class ACOTool { // 輸入數(shù)據(jù)類型 public static final int INPUT_CITY_NAME = 1; public static final int INPUT_CITY_DIS = 2; // 城市間距離鄰接矩陣 public static double[][] disMatrix; // 當(dāng)前時(shí)間 public static int currentTime; // 測試數(shù)據(jù)地址 private String filePath; // 螞蟻數(shù)量 private int antNum; // 控制參數(shù) private double alpha; private double beita; private double p; private double Q; // 隨機(jī)數(shù)產(chǎn)生器 private Random random; // 城市名稱集合,這里為了方便,將城市用數(shù)字表示 private ArrayList<String> totalCitys; // 所有的螞蟻集合 private ArrayList<Ant> totalAnts; // 城市間的信息素濃度矩陣,隨著時(shí)間的增多而減少 private double[][] pheromoneMatrix; // 目標(biāo)的最短路徑,順序?yàn)閺募系那安客笠苿?dòng) private ArrayList<String> bestPath; // 信息素矩陣存儲圖,key采取的格式(i,j,t)->value private Map<String, Double> pheromoneTimeMap; public ACOTool(String filePath, int antNum, double alpha, double beita, double p, double Q) { this.filePath = filePath; this.antNum = antNum; this.alpha = alpha; this.beita = beita; this.p = p; this.Q = Q; this.currentTime = 0; readDataFile(); } /** * 從文件中讀取數(shù)據(jù) */ private void readDataFile() { File file = new File(filePath); ArrayList<String[]> dataArray = new ArrayList<String[]>(); try { BufferedReader in = new BufferedReader(new FileReader(file)); String str; String[] tempArray; while ((str = in.readLine()) != null) { tempArray = str.split(" "); dataArray.add(tempArray); } in.close(); } catch (IOException e) { e.getStackTrace(); } int flag = ⑴; int src = 0; int des = 0; int size = 0; // 進(jìn)行城市名稱種數(shù)的統(tǒng)計(jì) this.totalCitys = new ArrayList<>(); for (String[] array : dataArray) { if (array[0].equals("#") && totalCitys.size() == 0) { flag = INPUT_CITY_NAME; continue; } else if (array[0].equals("#") && totalCitys.size() > 0) { size = totalCitys.size(); // 初始化距離矩陣 this.disMatrix = new double[size + 1][size + 1]; this.pheromoneMatrix = new double[size + 1][size + 1]; // 初始值⑴代表此對應(yīng)位置無值 for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { this.disMatrix[i][j] = ⑴; this.pheromoneMatrix[i][j] = ⑴; } } flag = INPUT_CITY_DIS; continue; } if (flag == INPUT_CITY_NAME) { this.totalCitys.add(array[0]); } else { src = Integer.parseInt(array[0]); des = Integer.parseInt(array[1]); this.disMatrix[src][des] = Double.parseDouble(array[2]); this.disMatrix[des][src] = Double.parseDouble(array[2]); } } } /** * 計(jì)算從螞蟻城市i到j(luò)的幾率 * * @param cityI * 城市I * @param cityJ * 城市J * @param currentTime * 當(dāng)前時(shí)間 * @return */ private double calIToJProbably(String cityI, String cityJ, int currentTime) { double pro = 0; double n = 0; double pheromone; int i; int j; i = Integer.parseInt(cityI); j = Integer.parseInt(cityJ); pheromone = getPheromone(currentTime, cityI, cityJ); n = 1.0 / disMatrix[i][j]; if (pheromone == 0) { pheromone = 1; } pro = Math.pow(n, alpha) * Math.pow(pheromone, beita); return pro; } /** * 計(jì)算綜合幾率螞蟻從I城市走到J城市的幾率 * * @return */ public String selectAntNextCity(Ant ant, int currentTime) { double randomNum; double tempPro; // 總幾率指數(shù) double proTotal; String nextCity = null; ArrayList<String> allowedCitys; // 各城市幾率集 double[] proArray; // 如果是剛剛開始的時(shí)候,沒有途經(jīng)任何城市,則隨機(jī)返回1個(gè)城市 if (ant.currentPath.size() == 0) { nextCity = String.valueOf(random.nextInt(totalCitys.size()) + 1); return nextCity; } else if (ant.nonVisitedCitys.isEmpty()) { // 如果全部遍歷終了,則再次回到出發(fā)點(diǎn) nextCity = ant.currentPath.get(0); return nextCity; } proTotal = 0; allowedCitys = ant.nonVisitedCitys; proArray = new double[allowedCitys.size()]; for (int i = 0; i < allowedCitys.size(); i++) { nextCity = allowedCitys.get(i); proArray[i] = calIToJProbably(ant.currentPos, nextCity, currentTime); proTotal += proArray[i]; } for (int i = 0; i < allowedCitys.size(); i++) { // 歸1化處理 proArray[i] /= proTotal; } // 用隨機(jī)數(shù)選擇下1個(gè)城市 randomNum = random.nextInt(100) + 1; randomNum = randomNum / 100; // 由于1.0是沒法判斷到的,,總和會(huì)無窮接近1.0取為0.99做判斷 if (randomNum == 1) { randomNum = randomNum - 0.01; } tempPro = 0; // 肯定區(qū)間 for (int j = 0; j < allowedCitys.size(); j++) { if (randomNum > tempPro && randomNum <= tempPro + proArray[j]) { // 采取拷貝的方式避免援用重復(fù) nextCity = allowedCitys.get(j); break; } else { tempPro += proArray[j]; } } return nextCity; } /** * 獲得給定時(shí)間點(diǎn)上從城市i到城市j的信息素濃度 * * @param t * @param cityI * @param cityJ * @return */ private double getPheromone(int t, String cityI, String cityJ) { double pheromone = 0; String key; // 上1周期需將時(shí)間倒回1周期 key = MessageFormat.format("{0},{1},{2}", cityI, cityJ, t); if (pheromoneTimeMap.containsKey(key)) { pheromone = pheromoneTimeMap.get(key); } return pheromone; } /** * 每輪結(jié)束,刷新信息素濃度矩陣 * * @param t */ private void refreshPheromone(int t) { double pheromone = 0; // 上1輪周期結(jié)束后的信息素濃度,叢信息素濃度圖中查找 double lastTimeP = 0; // 本輪信息素濃度增加量 double addPheromone; String key; for (String i : totalCitys) { for (String j : totalCitys) { if (!i.equals(j)) { // 上1周期需將時(shí)間倒回1周期 key = MessageFormat.format("{0},{1},{2}", i, j, t - 1); if (pheromoneTimeMap.containsKey(key)) { lastTimeP = pheromoneTimeMap.get(key); } else { lastTimeP = 0; } addPheromone = 0; for (Ant ant : totalAnts) { if(ant.pathContained(i, j)){ // 每只螞蟻傳播的信息素為控制因子除以距離總本錢 addPheromone += Q / ant.calSumDistance(); } } // 將上次的結(jié)果值加上遞增的量,并存入圖中 pheromone = p * lastTimeP + addPheromone; key = MessageFormat.format("{0},{1},{2}", i, j, t); pheromoneTimeMap.put(key, pheromone); } } } } /** * 蟻群算法迭代次數(shù) * @param loopCount * 具體遍歷次數(shù) */ public void antStartSearching(int loopCount) { // 蟻群尋覓的總次數(shù) int count = 0; // 選中的下1個(gè)城市 String selectedCity = ""; pheromoneTimeMap = new HashMap<String, Double>(); totalAnts = new ArrayList<>(); random = new Random(); while (count < loopCount) { initAnts(); while (true) { for (Ant ant : totalAnts) { selectedCity = selectAntNextCity(ant, currentTime); ant.goToNextCity(selectedCity); } // 如果已遍歷完所有城市,則跳出此輪循環(huán) if (totalAnts.get(0).isBack()) { break; } } // 周期時(shí)間疊加 currentTime++; refreshPheromone(currentTime); count++; } // 根據(jù)距離本錢,選出所花距離最短的1個(gè)路徑 Collections.sort(totalAnts); bestPath = totalAnts.get(0).currentPath; System.out.println(MessageFormat.format("經(jīng)過{0}次循環(huán)遍歷,終究得出的最好路徑:", count)); System.out.print("entrance"); for (String cityName : bestPath) { System.out.print(MessageFormat.format("-->{0}", cityName)); } } /** * 初始化蟻群操作 */ private void initAnts() { Ant tempAnt; ArrayList<String> nonVisitedCitys; totalAnts.clear(); // 初始化蟻群 for (int i = 0; i < antNum; i++) { nonVisitedCitys = (ArrayList<String>) totalCitys.clone(); tempAnt = new Ant(pheromoneMatrix, nonVisitedCitys); totalAnts.add(tempAnt); } } }

場景測試類Client.java:

package DataMining_ACO; /** * 蟻群算法測試類 * @author lyq * */ public class Client { public static void main(String[] args){ //測試數(shù)據(jù) String filePath = "C:UserslyqDesktopiconinput.txt"; //螞蟻數(shù)量 int antNum; //蟻群算法迭代次數(shù) int loopCount; //控制參數(shù) double alpha; double beita; double p; double Q; antNum = 3; alpha = 0.5; beita = 1; p = 0.5; Q = 5; loopCount = 5; ACOTool tool = new ACOTool(filePath, antNum, alpha, beita, p, Q); tool.antStartSearching(loopCount); } }

算法的輸出,就是在屢次搜索以后,找到的路徑中最短的1個(gè)路徑:

經(jīng)過5次循環(huán)遍歷,終究得出的最好路徑: entrance-->4-->1-->2-->3-->4

由于數(shù)據(jù)量比較小,其實(shí)不能看出蟻群算法在這方面的優(yōu)勢,博友們可以再次基礎(chǔ)上自行改造,并用大1點(diǎn)的數(shù)據(jù)做測試,其中的4個(gè)控制因子也能夠調(diào)控。蟻群算法作為1種啟發(fā)式算法,還可以和遺傳算法結(jié)合,創(chuàng)造出更優(yōu)的算法。蟻群算法可以解決許多這樣的連通圖路徑優(yōu)化問題。但是有的時(shí)候也會(huì)出現(xiàn)搜索時(shí)間太長的問題。


參考文獻(xiàn):百度百科.蟻群算法

我的數(shù)據(jù)發(fā)掘算法庫:https://github.com/linyiqun/DataMiningAlgorithm

我的算法庫:https://github.com/linyiqun/lyq-algorithms-lib


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 青青青青久久精品国产一百度 | 国产欧美一区二区三区免费看 | 免费中文字幕在线国语 | 看亚洲人配人配人种jizz | 国内精品一区二区三区东京 | 伊人网五月天 | 456亚洲人成在线播放网站 | 操操爱 | 成人hd | 国产真实偷乱小说 | 亚洲依依成人精品 | 国产精品午夜在线播放a | 亚洲一级二级三级 | 亚洲人成影院在线高清 | 欧美一级毛片日本 | 色人阁网站 | 冲田杏梨j和l超乳w真性中出 | 国产caob | 亚洲欧美卡通成人制服动漫 | 欧美性猛交乱大交xxxx | 日本最新免费网站 | 在线九色 | 免费不卡毛片 | 中文字幕首页 | 国产女人伦码一区二区三区不卡 | 动漫一级毛片 | 午夜视频www | 国语性猛交xxxx乱大交 | 久久国产精品免费视频 | 国产精久久一区二区三区 | 午夜理伦三级播放 | 久草三级| 97欧美在线看欧美视频免费 | 亚洲人网 | 精品欧美一区二区三区在线 | 黑人高h| 最近高清中文字幕大全1 | 最近中文字幕大全2019 | 国产欧美一区二区三区视频在线观看 | 欧美黑粗特黄午夜大片 | 黄色小说区|