zoukankan      html  css  js  c++  java
  • 算法问题基于蚁群算法求解求解TSP问题(JAVA)

    这两天一直在查找算法问题之类的问题,现在正好有机会和大家分享一下.

        一、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),全部的节点一次并且回到始起节点,使得连接这些节点的路径本钱最低。

        

        二、蚁群算法

        蚁群算法(ant colony optimization, ACO),又称蚂蚁算法,是一种用来在图中找寻化优路径的机率型算法。它由Marco Dorigo于1992年在他的博士论文中提出,其灵感来源于蚂蚁在找寻物食程过中发明路径的行为。蚁群算法是一种模拟化进算法,步初的研讨明表该算法有具很多优秀的性子。针对PID制控器数参化优计设问题,将蚁群算法计设的结果与遗传算法计设的结果停止了较比,值数仿真结果明表,蚁群算法有具一种新的模拟化进化优方法的有效性和应用值价。

        蚁群算法道理:假如蚁群中全部蚂蚁的量数为m,全部都会之间的信息素用阵矩pheromone表现,最短路径为bestLength,最好路径为bestTour。每只蚂蚁都有自己的内存,内存用中一个忌禁表(Tabu)来存储该蚂蚁经已问访过的都会,表现其在后以的搜索中将不能问访这些都会;还用有另外一个许允问访的都会表(Allowed)来存储它还可以问访的都会;另外还用一个阵矩(Delta)来存储它在一个循环(或者代迭)中给所经过的路径释放的信息素;还有另外一些数据,例如一些制控数参(α,β,ρ,Q),该蚂蚁行走玩全程的总本钱或离距(tourLength),等等。定假算法共总运行MAX_GEN次,运行间时为t。

        蚁群算法盘算程过如下:
    (1)初始化
    (2)为每只蚂蚁选择下一个节点。
    (3)新更信息素阵矩
    (4)检查终止条件
    (5)输出最优值

        三、蚁群算法求解TSP问题

        在该JAVA现实中我们选择应用tsplib上的数据att48,这是一个对称TSP问题,都会规模为48,其最优值为10628.其离距盘算方法下图所示:

        算法和问题

        详细代码如下:

    package noah;
    
    import java.util.Random;
    import java.util.Vector;
    
    public class Ant implements Cloneable {
    
    	private Vector<Integer> tabu; // 忌禁表
    	private Vector<Integer> allowedCities; // 许允搜索的都会
    	private float[][] delta; // 信息数化变阵矩
    	private int[][] distance; // 离距阵矩
    	private float alpha;
    	private float beta;
    
    	private int tourLength; // 路径长度
    	private int cityNum; // 都会量数
    	private int firstCity; // 始起都会
    	private int currentCity; // 后以都会
    
    	public Ant() {
    		cityNum = 30;
    		tourLength = 0;
    	}
    
    	/**
    	 * Constructor of Ant
    	 * 
    	 * @param num
    	 *            蚂蚁量数
    	 */
    	public Ant(int num) {
    		cityNum = num;
    		tourLength = 0;
    	}
    
    	/**
    	 * 初始化蚂蚁,随机选择始起位置
    	 * 
    	 * @param distance
    	 *            离距阵矩
    	 * @param a
    	 *            alpha
    	 * @param b
    	 *            beta
    	 */
    
    	public void init(int[][] distance, float a, float b) {
    		alpha = a;
    		beta = b;
    		// 初始许允搜索的都会合集
    		allowedCities = new Vector<Integer>();
    		// 初始忌禁表
    		tabu = new Vector<Integer>();
    		// 初始离距阵矩
    		this.distance = distance;
    		// 初始信息数化变阵矩为0
    		delta = new float[cityNum][cityNum];
    		for (int i = 0; i < cityNum; i++) {
    			Integer integer = new Integer(i);
    			allowedCities.add(integer);
    			for (int j = 0; j < cityNum; j++) {
    				delta[i][j] = 0.f;
    			}
    		}
    		// 随机挑选一个都会作为始起都会
    		Random random = new Random(System.currentTimeMillis());
    		firstCity = random.nextInt(cityNum);
    		// 许允搜索的都会合集中移除始起都会
    		for (Integer i : allowedCities) {
    			if (i.intValue() == firstCity) {
    				allowedCities.remove(i);
    				break;
    			}
    		}
    		// 将始起都会加添至忌禁表
    		tabu.add(Integer.valueOf(firstCity));
    		// 后以都会为始起都会
    		currentCity = firstCity;
    	}
    
    	/**
    	 * 
    	 * 选择下一个都会
    	 * 
    	 * @param pheromone
    	 *            信息素阵矩
    	 */
    
    	public void selectNextCity(float[][] pheromone) {
    		float[] p = new float[cityNum];
    		float sum = 0.0f;
    		// 盘算分母分部
    		for (Integer i : allowedCities) {
    			sum += Math.pow(pheromone[currentCity][i.intValue()], alpha)
    					* Math.pow(1.0 / distance[currentCity][i.intValue()], beta);
    		}
    		// 盘算概率阵矩
    		for (int i = 0; i < cityNum; i++) {
    			boolean flag = false;
    			for (Integer j : allowedCities) {
    				if (i == j.intValue()) {
    					p[i] = (float) (Math.pow(pheromone[currentCity][i], alpha) * Math
    							.pow(1.0 / distance[currentCity][i], beta)) / sum;
    					flag = true;
    					break;
    				}
    			}
    			if (flag == false) {
    				p[i] = 0.f;
    			}
    		}
    		// 轮盘赌选择下一个都会
    		Random random = new Random(System.currentTimeMillis());
    		float sleectP = random.nextFloat();
    		int selectCity = 0;
    		float sum1 = 0.f;
    		for (int i = 0; i < cityNum; i++) {
    			sum1 += p[i];
    			if (sum1 >= sleectP) {
    				selectCity = i;
    				break;
    			}
    		}
    		// 从许允选择的都会中去除select city
    		for (Integer i : allowedCities) {
    			if (i.intValue() == selectCity) {
    				allowedCities.remove(i);
    				break;
    			}
    		}
    		// 在忌禁表中加添select city
    		tabu.add(Integer.valueOf(selectCity));
    		// 将后以都会改成选择的都会
    		currentCity = selectCity;
    	}
    
    	/**
    	 * 盘算路径长度
    	 * 
    	 * @return 路径长度
    	 */
    	private int calculateTourLength() {
    		int len = 0;
    		//忌禁表tabu终最式形:始起都会,都会1,都会2...都会n,始起都会
    		for (int i = 0; i < cityNum; i++) {
    			len += distance[this.tabu.get(i).intValue()][this.tabu.get(i + 1)
    					.intValue()];
    		}
    		return len;
    	}
    
    	public Vector<Integer> getAllowedCities() {
    		return allowedCities;
    	}
    
    	public void setAllowedCities(Vector<Integer> allowedCities) {
    		this.allowedCities = allowedCities;
    	}
    
    	public int getTourLength() {
    		tourLength = calculateTourLength();
    		return tourLength;
    	}
    
    	public void setTourLength(int tourLength) {
    		this.tourLength = tourLength;
    	}
    
    	public int getCityNum() {
    		return cityNum;
    	}
    
    	public void setCityNum(int cityNum) {
    		this.cityNum = cityNum;
    	}
    
    	public Vector<Integer> getTabu() {
    		return tabu;
    	}
    
    	public void setTabu(Vector<Integer> tabu) {
    		this.tabu = tabu;
    	}
    
    	public float[][] getDelta() {
    		return delta;
    	}
    
    	public void setDelta(float[][] delta) {
    		this.delta = delta;
    	}
    
    	public int getFirstCity() {
    		return firstCity;
    	}
    
    	public void setFirstCity(int firstCity) {
    		this.firstCity = firstCity;
    	}
    
    }
        每日一道理
    美丽是平凡的,平凡得让你感觉不到她的存在;美丽是平淡的,平淡得只剩下温馨的回忆;美丽又是平静的,平静得只有你费尽心思才能激起她的涟漪。
    package noah;
    
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class ACO {
    
    	private Ant[] ants; // 蚂蚁
    	private int antNum; // 蚂蚁量数
    	private int cityNum; // 都会量数
    	private int MAX_GEN; // 运行代数
    	private float[][] pheromone; // 信息素阵矩
    	private int[][] distance; // 离距阵矩
    	private int bestLength; // 最好长度
    	private int[] bestTour; // 最好路径
    
    	// 三个数参
    	private float alpha;
    	private float beta;
    	private float rho;
    
    	public ACO() {
    
    	}
    
    	/**
    	 * constructor of ACO
    	 * 
    	 * @param n
    	 *            都会量数
    	 * @param m
    	 *            蚂蚁量数
    	 * @param g
    	 *            运行代数
    	 * @param a
    	 *            alpha
    	 * @param b
    	 *            beta
    	 * @param r
    	 *            rho
    	 * 
    	 **/
    	public ACO(int n, int m, int g, float a, float b, float r) {
    		cityNum = n;
    		antNum = m;
    		ants = new Ant[antNum];
    		MAX_GEN = g;
    		alpha = a;
    		beta = b;
    		rho = r;
    	}
    
    	// 给编译器一条指令,诉告它对被注批的代码素元部内的某些正告持保静默
    	@SuppressWarnings("resource")
    	/**
    	 * 初始化ACO算法类
    	 * @param filename 数据件文名,该件文存储全部都会节点坐标数据
    	 * @throws IOException
    	 */
    	private void init(String filename) throws IOException {
    		// 读取数据
    		int[] x;
    		int[] y;
    		String strbuff;
    		BufferedReader data = new BufferedReader(new InputStreamReader(
    				new FileInputStream(filename)));
    		distance = new int[cityNum][cityNum];
    		x = new int[cityNum];
    		y = new int[cityNum];
    		for (int i = 0; i < cityNum; i++) {
    			// 读取一行数据,数据格式1 6734 1453
    			strbuff = data.readLine();
    			// 字符割分
    			String[] strcol = strbuff.split(" ");
    			x[i] = Integer.valueOf(strcol[1]);// x坐标
    			y[i] = Integer.valueOf(strcol[2]);// y坐标
    		}
    		// 盘算离距阵矩
    		// 针对详细问题,离距盘算方法也不一样,此处用的是att48作为案例,它有48个都会,离距盘算方法为伪欧氏离距,最优值为10628
    		for (int i = 0; i < cityNum - 1; i++) {
    			distance[i][i] = 0; // 对角线为0
    			for (int j = i + 1; j < cityNum; j++) {
    				double rij = Math
    						.sqrt(((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j])
    								* (y[i] - y[j])) / 10.0);
    				// 四舍五入,取整
    				int tij = (int) Math.round(rij);
    				if (tij < rij) {
    					distance[i][j] = tij + 1;
    					distance[j][i] = distance[i][j];
    				} else {
    					distance[i][j] = tij;
    					distance[j][i] = distance[i][j];
    				}
    			}
    		}
    		distance[cityNum - 1][cityNum - 1] = 0;
    		// 初始化信息素阵矩
    		pheromone = new float[cityNum][cityNum];
    		for (int i = 0; i < cityNum; i++) {
    			for (int j = 0; j < cityNum; j++) {
    				pheromone[i][j] = 0.1f; // 初始化为0.1
    			}
    		}
    		bestLength = Integer.MAX_VALUE;
    		bestTour = new int[cityNum + 1];
    		// 随机放置蚂蚁
    		for (int i = 0; i < antNum; i++) {
    			ants[i] = new Ant(cityNum);
    			ants[i].init(distance, alpha, beta);
    		}
    	}
    
    	public void solve() {
    		// 代迭MAX_GEN次
    		for (int g = 0; g < MAX_GEN; g++) {
    			// antNum只蚂蚁
    			for (int i = 0; i < antNum; i++) {
    				// i这只蚂蚁走cityNum步,整完一个TSP
    				for (int j = 1; j < cityNum; j++) {
    					ants[i].selectNextCity(pheromone);
    				}
    				// 把这只蚂蚁始起都会参加其忌禁表中
    				// 忌禁表终最式形:始起都会,都会1,都会2...都会n,始起都会
    				ants[i].getTabu().add(ants[i].getFirstCity());
    				// 看查这只蚂蚁行走路径离距是不是比后以离距优秀
    				if (ants[i].getTourLength() < bestLength) {
    					// 比后以优秀则贝拷优秀TSP路径
    					bestLength = ants[i].getTourLength();
    					for (int k = 0; k < cityNum + 1; k++) {
    						bestTour[k] = ants[i].getTabu().get(k).intValue();
    					}
    				}
    				// 新更这只蚂蚁的信息数化变阵矩,对称阵矩
    				for (int j = 0; j < cityNum; j++) {
    					ants[i].getDelta()[ants[i].getTabu().get(j).intValue()][ants[i]
    							.getTabu().get(j + 1).intValue()] = (float) (1. / ants[i]
    							.getTourLength());
    					ants[i].getDelta()[ants[i].getTabu().get(j + 1).intValue()][ants[i]
    							.getTabu().get(j).intValue()] = (float) (1. / ants[i]
    							.getTourLength());
    				}
    			}
    			// 新更信息素
    			updatePheromone();
    			// 从新初始化蚂蚁
    			for (int i = 0; i < antNum; i++) {
    				ants[i].init(distance, alpha, beta);
    			}
    		}
    
    		// 打印最好结果
    		printOptimal();
    	}
    
    	// 新更信息素
    	private void updatePheromone() {
    		// 信息素挥发
    		for (int i = 0; i < cityNum; i++)
    			for (int j = 0; j < cityNum; j++)
    				pheromone[i][j] = pheromone[i][j] * (1 - rho);
    		// 信息素新更
    		for (int i = 0; i < cityNum; i++) {
    			for (int j = 0; j < cityNum; j++) {
    				for (int k = 0; k < antNum; k++) {
    					pheromone[i][j] += ants[k].getDelta()[i][j];
    				}
    			}
    		}
    	}
    
    	private void printOptimal() {
    		System.out.println("The optimal length is: " + bestLength);
    		System.out.println("The optimal tour is: ");
    		for (int i = 0; i < cityNum + 1; i++) {
    			System.out.println(bestTour[i]);
    		}
    	}
    
    
    	/**
    	 * @param args
    	 * @throws IOException
    	 */
    	public static void main(String[] args) throws IOException {
    		System.out.println("Start....");
    		ACO aco = new ACO(48, 10, 100, 1.f, 5.f, 0.5f);
    		aco.init("c://data.txt");
    		aco.solve();
    	}
    
    }

        运行结果截图:

        算法和问题

        四、结总

        蚁群算法是一种实质上并行的算法。每只蚂蚁搜索的程过彼此独立,仅通过信息激素停止通信。所以蚁群算法则可以作看是一个分布式的多agent系统,它在问题空间的点多同时开始停止独立的解搜索,不仅增加了算法的可靠性,也使得算法有具较强的全局搜索能力,但是也恰是由于其并行性的实质,蚁群算法的搜索间时较长,在求解小规模的NP问题时消耗的盘算资源比相其他启发式算法要多,因而显得效率很低下,而当问题趋向于大规模时,蚁群算法还是存在难收敛的问题,个人感觉除非你真想消耗量大盘算资源来干一件事件,否则还是慎用蚁群算法。

        注:本文分部内容来源于络网,但程序以及分析结果属于本人果成,转载请注明!

        

    文章结束给大家分享下程序员的一些笑话语录: 关于编程语言
    如果 C++是一把锤子的话,那么编程就会变成大手指头。
    如果你找了一百万只猴子来敲打一百万个键盘,那么会有一只猴子会敲出一 段 Java 程序,而其余的只会敲出 Perl 程序。
    一阵急促的敲门声,“谁啊!”,过了 5 分钟,门外传来“Java”。
    如果说 Java 很不错是因为它可以运行在所有的操作系统上,那么就可以说 肛交很不错,因为其可以使用于所有的性别上。

  • 相关阅读:
    HTML页面跳转的5种方法
    ngixn配置
    redis秒杀
    php 设计模式
    MySQL之事务的四大特性
    [置顶] JNI之java传递数据给c语言
    jQuery 快速结束当前动画
    编绎OpenJDK
    CF#231DIV2:A Good Number
    CF#213DIV2:B The Fibonacci Segment
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3057252.html
Copyright © 2011-2022 走看看