改进的蚁群算法Java——求解2016 code craft华为精英挑战赛初赛题目

小白参加了2016 code craft华为精英挑战赛,一个人码了四五天,无奈只获得京津赛区51名,在这里将代码贴出来,供交流参考。希望多提宝贵意见,谢谢。

 

改进思路:

         传统蚁群算法依靠信息素选择路径,但是当地图规模很大时,蚂蚁很难成功到达终点同时经过所有要求点,因此不会在路径上留下信息素给后边的蚂蚁提供有效的启发。因此改进算法引入环境素(condiInfors)的概念,环境素包含要求点的信息,要求点向外扩散相应的环境素,当蚂蚁发现周围存在自己没有到达过的要求点对应的信息素时,将该点设置为临时目标,向该点移动。通过这种方法提高第一只蚂蚁到达终点同时经过所有要求点的可能性。在初始阶段,所有蚂蚁参考环境素寻找路径,当第一只蚂蚁成功后留下信息素,再调整所有蚂蚁参考信息素,以优化该路径。

 

程序流程:

1.解析文件字符串

2.生成有向图sideMap,剪枝操作,并初步判断是否有可行解

3.开始搜索路径

3.1.每个蚂蚁尝试寻找

按照概率选择寻找方式(信息素or环境素)

3.2.将成功蚂蚁的路径保存下来

3.3.更新信息素


<span style="font-size:12px;">package com.routesearch.route;

/**
 * 有向边类
 * @author Hao
 *
 */
public class Side {
	//边的起点
	private int from;
	//边的重点
	private int to;

	/**
	 * 构造方法
	 */
	public Side(){
		
	}
	public Side(int from,int to){
		this.from = from;
		this.to = to;
	}

	
	
	public int getFrom() {
		return from;
	}

	public int getTo() {
		return to;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + from;
		result = prime * result + to;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Side other = (Side) obj;
		if (from != other.from)
			return false;
		if (to != other.to)
			return false;
		return true;
	}
	public boolean equals(int from,int to){
		if(from == this.from){
			if(to == this.to){
				return true;
			}
		}
		return false;
	}
	
	
	@Override
	public String toString() {
		return "Side [from=" + from + ", to=" + to  + "]";
	}
}
</span>

package com.routesearch.route;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 边集类
 * @author Hao
 *
 */
public class SideMap {
	
	//维护边与对应权重的哈希Map
	private Map<Side,Integer> sides;
	
	//维护边与对应信息素的Map
	private Map<Side,Double> infors;

	//维护边与编号的Map
	private Map<Side,Integer> nums;
	
	//维护每个节点可达的要求点或终点,key:节点  value:要求点可达Map(key可达点,value多少步可以到达)
	private Map<Integer,Map<Integer,Integer>> condiInfors;
	
	//enterNeighbors,相邻入节点Map,key:节点,value:相邻入节点集合
	private Map<Integer,Set<Integer>> enterNeighbors;
	
	//exitNeighbors,相邻出节点Map,key:节点,value:相邻出节点集合
	private Map<Integer,Set<Integer>> exitNeighbors;	
	
	//构建condiInfor时的循环次数
	private static final int condiInforNum = 5;
	/**
	 * 构造方法
	 * 改进,识别显然NA的情况:要求点没有出路或没有入路
	 * @param data
	 */
	public SideMap(String strData){
		sides = new HashMap<Side,Integer>();
		infors = new HashMap<Side,Double>();
		nums = new HashMap<Side,Integer>();
		condiInfors = new HashMap<Integer,Map<Integer,Integer>>();
		exitNeighbors = new HashMap<Integer,Set<Integer>>();	
		enterNeighbors = new HashMap<Integer,Set<Integer>>();
		String[] data = strData.split("\n");
		
		for(int i = 0;i < data.length;i ++){
			String[] line = data[i].split(",");
			int from = Integer.parseInt(line[1]);
			
			//如果边的from是终点,则跳过
			if(from == Ant.end){
				continue;
			}
			
			int to = Integer.parseInt(line[2]);
			
			//如果边的to是起点,则跳过
			if(to == Ant.start)
				continue;
			
			//如果enterNeighbors不包含to
			if(!enterNeighbors.containsKey(Integer.valueOf(to))){
				enterNeighbors.put(to, new HashSet<Integer>());
			}
			
			//添加相邻入节点
			enterNeighbors.get(Integer.valueOf(to)).add(from);
			
			//修改相邻出节点Map
			if(!exitNeighbors.containsKey(Integer.valueOf(from))){
				exitNeighbors.put(from, new HashSet<Integer>());
			}
			
			exitNeighbors.get(Integer.valueOf(from)).add(to);
			
			int weight = Integer.parseInt(line[3]);
			Side side = new Side(from, to);

			//如果sides中已经包含side,比较权重
			if(sides.containsKey(side)){
				//若新side权重较小,则替换
				if(sides.get(side) > weight){
					sides.put(side, weight);
					infors.put(side, 0.03);
					nums.put(side, i);
				}
			}else{
				sides.put(side, weight);
				infors.put(side, 0.03);
				nums.put(side, i);
			}
		}
		
		//剪枝操作
		while(removeSides());
		//可行性检查
		if(!checkCondiPointEnterExit()){
			AntSearch.over = true;
			return;
		}else{
			AntSearch.over = false;
		}
		conditionPointSpread();
	}
	
	/**
	 * 检查要求点的入度和出度,如果存在要求点没有入度或出度返回false
	 * @return
	 */
	public boolean checkCondiPointEnterExit(){
		//检查起点出度
		if(!exitNeighbors.containsKey(Integer.valueOf(Ant.start))){
			return false;
		}
		//检查终点入度
		if(!enterNeighbors.containsKey(Integer.valueOf(Ant.end))){
			return false;
		}
		//检查要求点的出度入度
		for(int i = 0;i < AntSearch.conditionPoints.size();i ++){
			int condiPoint = AntSearch.conditionPoints.get(i);
			if(!exitNeighbors.containsKey(Integer.valueOf(condiPoint))){
				return false;
			}
			if(!enterNeighbors.containsKey(Integer.valueOf(condiPoint))){
				return false;
			}
		}
		return true;
	}
	
	
	/**
	 * 剪枝操作:删除没有出度节点对应的边,如果有删除操作,则返回true
	 * @param exitNeighbors
	 */
	public boolean removeSides(){
		boolean flag = false;
		//要删除的边放入集合
		Set<Side> removeSide = new HashSet<Side>();
		for(Side side:sides.keySet()){
			int to = side.getTo();
			//如果边的末端没有出度且不是终点
			if(!exitNeighbors.containsKey(Integer.valueOf(to))){
				if(to!= Ant.end)
					removeSide.add(side);
			}
			//删除出度入度为1且相同的节点
			else if(exitNeighbors.get(Integer.valueOf(to)).size() == 1){
				int to2 = exitNeighbors.get(Integer.valueOf(to)).toArray(new Integer[0])[0];
				if(to2 == side.getFrom()){
					removeSide.add(side);
				}
			}
		}
		//删除末端节点没有出度的边
		for(Side side:removeSide){
			flag = true;
			//System.out.println("Remove: "+side);
			sides.remove(side);
			infors.remove(side);
			nums.remove(side);
		}
		//重新统计exitNeighbors
		if(flag){
			getExitNeighbors();			
		}
		return flag;
	}
	
	/**
	 * 重新统计exitNeighbors
	 */
	public void getExitNeighbors(){
		exitNeighbors.clear();
		for(Side side:sides.keySet()){
			int from = side.getFrom();
			int to = side.getTo();
			if(!exitNeighbors.containsKey(Integer.valueOf(from))){
				exitNeighbors.put(from, new HashSet<Integer>());
			}
			exitNeighbors.get(Integer.valueOf(from)).add(Integer.valueOf(to));
		}
	}
	
	/**
	 * 由相邻入节点Map,统计各个节点可达的要求点或终点
	 * @param enterNeighbors,相邻入节点Map,key:节点,value:相邻入节点集合
	 */
	public void conditionPointSpread(){
		
		//声明要求点和终点的集合
		Set<Integer> conditionPoints = new HashSet<Integer>(AntSearch.conditionPoints);
		conditionPoints.add(Ant.end);
		
		//对于集合中的每一个顶点
		for(Integer point:conditionPoints){
			
			//遍历过的节点放入closeSet中
			Set<Integer> closeSet = new HashSet<Integer>();
			
			//point的相邻入节点放入openSet中
			Set<Integer> openSet = new HashSet<Integer>(enterNeighbors.get(Integer.valueOf(point)));
			
			//当openSet非空,执行循环
			//while(!openSet.isEmpty()){
			//将要求点的信息扩散到condiInforNum层
			for(int floorNum = 1;floorNum < condiInforNum;floorNum ++){
				//临时open表
				Set<Integer> openSetTemp = new HashSet<Integer>();
				
				//对open表中的每一个元素
				for(Integer p:openSet){
					//声明可达节点集合
					if(!condiInfors.containsKey(Integer.valueOf(p))){
						condiInfors.put(p, new HashMap<Integer,Integer>());
					}
					//记录方式1,3,5
					condiInfors.get(Integer.valueOf(p)).put(point, floorNum*3 - 1);
					
					//将p的相邻入节点加入openSetTemp表,由于HashSet元素不可重复,会不重复添加
					if(enterNeighbors.containsKey(Integer.valueOf(p))){
						Set<Integer> enterNeighbor = new HashSet<Integer>(enterNeighbors.get(Integer.valueOf(p)));
						openSetTemp.addAll(enterNeighbor);
						
						//从openSet中删除closeSet表,防止重复添加
						openSetTemp.removeAll(closeSet);
					}
					//将p加入closeSet中
					closeSet.add(p);
				}
				//将openSetTemp放入openSet
				openSet = new HashSet<Integer>(openSetTemp);
			}

		}
	}
	

	/**
	 * 将以必须经过的顶点为to的边的信息素设置为1,将to为其相邻入节点的信息素设置为0.7--改进
	 * @param conditions
	 */
	public void setConditionSide(List<Integer> conditions){
		for(int i = 0;i < conditions.size();i ++){
//			int conditionPoint = conditions.get(i);
//			for(Side s: sides.keySet()){
//				if(s.getTo() == conditionPoint){
//					infors.put(s, 1.0);
//				}
//			}
			//取其相邻入节点
//			Set<Integer> condiNeighbors = new HashSet<Integer>(enterNeighbors.get(conditionPoint));
//			for(Integer condiNeighbor:condiNeighbors){
//				if(!conditions.contains(condiNeighbor)){
//					for(Side s:sides.keySet()){
//						if(s.getTo() == condiNeighbor){
//							infors.put(s, 0.1);
//						}
//					}
//				}
//			}
		}
	}
	
	/**
	 * 搜索该点的邻居节点,且将List集合中的元素除去
	 * @param from
	 * @param path
	 * @param allConditionPoints 蚂蚁是否经过了全部要求点,如果否,则neighbors禁止包含终点
	 * @return
	 */
	public List<Integer> neighbors(int from,List<Integer> path,boolean allConditionPoints){
		
		//从出度Map中获取neighbors
		List<Integer> neighbors = new ArrayList<Integer>(exitNeighbors.get(Integer.valueOf(from)));
		
		//从neighbors中除去List
		neighbors.removeAll(path);
		
		//如果没有抵达所有目标点
		if(!allConditionPoints){
			neighbors.remove(Integer.valueOf(Ant.end));
		}
		
		return neighbors;
	}
	
	/**
	 * 获取from到to边的权值
	 * 若不存在则返回-1
	 * @param from
	 * @param to
	 * @return
	 */
	public int getWeight(int from,int to){
		int weight = -1;
		if(sides.get(new Side(from, to)) != null)
			weight = sides.get(new Side(from, to));
		return weight;
	}
	
	public double getInfor(int from,int to){
		return infors.get(new Side(from,to));
	}
	
	public double getInfor(Side side){
		return infors.get(side);
	}
	
	public void setInfor(int from,int to,double infor){
		setInfor(new Side(from,to), infor);
	}

	public Map<Integer, Map<Integer,Integer>> getCondiInfors() {
		return condiInfors;
	}
	
	public Map<Side, Double> getInfors() {
		return infors;
	}
	
	public void setInfor(Side side,double infor){
		//设置最小值和最大值
		if(infor < 0.03)
			infor = 0.03;
		if(infor > 0.7)
			infor = 0.7;
		infors.put(side, infor);
	}
	
	/**
	 * 信息素按照rou进行挥发,当前最佳路径上的信息素不挥发
	 * @param rou
	 */
	public void volatilize(double rou){

		for(Side s:sides.keySet()){
			if(!AntSearch.bestPathSide.contains(s))
				setInfor(s,getInfor(s)*rou);
		}
	}
	public void initInfor(){
		for(Side s:infors.keySet()){
			if(!AntSearch.bestPathSide.contains(s))
				setInfor(s,0.0);
		}
	}
	public int getNum(int from,int to){
		return nums.get(new Side(from,to));
	}
}


package com.routesearch.route;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 蚂蚁类
 * @author Hao
 *
 */
public class Ant {
	/**
	 * test
	 */
	public boolean chooseMethodFlag;
	
	//蚂蚁路径
	private List<Integer> path;
	
	//路径总长度
	private int pathLength;
	
	//信息素浓度作用系数
	private static final int alpha = 1;
	
	//期望值所起作用的程度
	private static final int beta = 1;//=0消除选择路径时权重的作用,由信息素决定路径的选择

	//蚂蚁还需要到达的要求点集合
	private List<Integer> condiPointsOpenList;
	
	//蚂蚁是否已经经过所有要求点
	private boolean allConditionPoints;
	
	//起点
	protected static int start;
	
	//终点
	protected static int end;
	
	//当前位置
	private int currentPoint;
	
	//专注要求点,蚂蚁在发现周围有要求点信息时,锁定一个要求点一直走,直到到达该要求点
	private int tempDistPoint;
	
	/**
	 * 常量,当MAX_COUNT内没有出现新路径,则初始化信息素
	 */
	public static final int MAX_COUNT = 600;
	
	/**
	 * 设置起点和终点,同时根据起始点判断解是否存在
	 */
	public static void setStartEnd(int start,int end){
		Ant.start = start;
		Ant.end = end;
	}
	
	/**
	 * 构造函数
	 */
	public Ant(){
		reset();
	}
	
	/**
	 * 重置蚂蚁
	 */
	public void reset(){
		tempDistPoint = -1;
		path = new ArrayList<Integer>();
		path.add(start);
		pathLength = 0;
		currentPoint = start;
		allConditionPoints = false;
		condiPointsOpenList = new ArrayList<Integer>(AntSearch.conditionPoints);
	}
	
	public List<Integer> getPath() {
		List<Integer> path = new ArrayList<Integer>(this.path);
		return path;
	}
	
	public int getPathLength() {
		return pathLength;
	}

	/**
	 * 蚂蚁移动一步,添加到path节点,更新pathLength
	 * 返回值表示蚂蚁有没有到达终点
	 * @param next
	 * @param sides
	 */
	public boolean move(int next,SideMap sideMap){

		int weight = sideMap.getWeight(currentPoint, next);
		if(weight != -1){
			path.add(next);
			currentPoint = next;
			//如果该点是要求点
			if(checkCondiPoint(currentPoint)){
				//在open表中删除该节点
				condiPointsOpenList.remove(Integer.valueOf(currentPoint));
				//修改专注点
				tempDistPoint = -1;
				//如果经过了所有要求点
				if(condiPointsOpenList.isEmpty()){
					allConditionPoints = true;
					//将终点加入open表
					condiPointsOpenList.add(end);
				}
			}
			pathLength += weight;
			if(next == end){
				return true;
			}
		}else{
			throw new RuntimeException("蚂蚁:没有这样的路径,移动下一步失败");
		}
		return false;
	}
		
	/**
	 * 检查当前点是否为要求点
	 */
	public boolean checkCondiPoint(int point){
		return AntSearch.conditionPoints.contains(Integer.valueOf(point));
	}

	/**
	 * 计算到给定点的概率
	 * @param to
	 * @param sideMap
	 * @return
	 */
	public double probab(int to,SideMap sideMap){
		double probability = 0;
		probability = Math.pow(1.0/sideMap.getWeight(currentPoint, to), beta)*
				Math.pow(sideMap.getInfor(currentPoint, to), alpha);
		if(probability <= 0){
			//说明没有蚂蚁走过,只按照距离选择
			probability = Math.pow(1.0/sideMap.getWeight(currentPoint, to), beta);
		}
		return probability;
	}
	
	/**
	 * 基于环境素选择下一个顶点
	 * @param sideMap
	 * @return
	 */
	public int chooseNextPoint(SideMap sideMap){
		//要到达下一个顶点
		int to = -1;
		
		//获取邻居节点
		List<Integer> neighbors = sideMap.neighbors(currentPoint, path,true);
		
		//如果没有可走的顶点,返回-1
		if(neighbors.size() == 0){
			return to;
		}
		//如果只有一种选择
		if(neighbors.size() == 0){
			return neighbors.get(0);
		}
		//极小的概率随机移动
		if(Math.random() < 0.15){
			tempDistPoint = -1;
			return neighbors.get((int)(Math.random()*neighbors.size()));
		}

		//邻居中包含要求点,则必须选择该点--添加概率
		int cond = -1;
		if((cond = hasCondition(neighbors))!=-1){
			if(Math.random()>0.05){
				return cond;
			}else{
				//背离要求点
				
			}
		}
		//如果要求点不为-1,则说明一定有邻居包含要求点信息,选择一个信息距离最小的作为to
//		tempDistPoint = -1;
		if(tempDistPoint != -1){
			//最小信息距离
			int minDistance = Integer.MAX_VALUE;
			for(int i = 0;i < neighbors.size();i ++){
				int neighbor = neighbors.get(i);
				//取环境素
				if(sideMap.getCondiInfors().containsKey(Integer.valueOf(neighbor))){
					Map<Integer,Integer> condiInfor = new HashMap<Integer,Integer>(sideMap.getCondiInfors().get(Integer.valueOf(neighbor)));
					//如果邻居包含专注点的信息
					if(condiInfor.containsKey(tempDistPoint)){
						//判断是否为最小距离
						if(minDistance > condiInfor.get(tempDistPoint)){
							minDistance = condiInfor.get(tempDistPoint);
							to = neighbor;
						}
					}
				}
			}
		}
		
		//若没有专注点
		else{
			//对每一个邻居
			for(int i = 0;i < neighbors.size();i ++){
				int neighbor = neighbors.get(i);
				//取环境素
				if(sideMap.getCondiInfors().containsKey(Integer.valueOf(neighbor))){
					Map<Integer,Integer> condiInfor = new HashMap<Integer,Integer>(sideMap.getCondiInfors().get(Integer.valueOf(neighbor)));
					for(Integer infor:condiInfor.keySet()){
						//如果open表中包含该环境素
						if(condiPointsOpenList.contains(Integer.valueOf(infor))){
							to = neighbor;
							//定义专注点
							tempDistPoint = infor;
							//按照该点到要求点的距离,随机选取要去的点
							double probab = 0.5/condiInfor.get(infor);
							if(Math.random() < probab){
								return to;
							}
						}
					}
				}
			}
		}

		
		//如果邻居没有open表中的环境素,随机选择一个邻居作为下一个节点
		if(to == -1){
			to = neighbors.get((int)(Math.random()*neighbors.size()));
		}
		
		return to;
	}
	
	
	/**
	 * 基于蚂蚁信息素选择下一个顶点,当无路可走时返回-1
	 * @param updateCount 
	 * 计数 当若干次没有产生新路径时,初始化信息素
	 * @param sideMap
	 * @param rou
	 * @return
	 */
	public int chooseNextPoint(int updateCount,SideMap sideMap){
		//要到达下一个顶点
		int to = -1;
		//信息素总量(分母)
		double sumInfor = 0.0;
		
		//寻找当前邻居顶点
		List<Integer> neighbors = sideMap.neighbors(currentPoint, path,true);
		
		//如果没有可走的顶点,返回-1
		if(neighbors.size() == 0){
			return to;
		}
		
		//如果只有一种选择
		if(neighbors.size() == 0){
			return neighbors.get(0);
		}
		
		//邻居中包含要求点,则必须选择该点--概率
		int cond = -1;
		if((cond = hasCondition(neighbors))!=-1){
			if(Math.random() > 0.1){
				return cond;
			}
		}
		
		//map存储概率
		Map<Integer,Double> probabMap = new HashMap<Integer,Double>();
		for(int neighbor :neighbors){
			double prob = probab(neighbor, sideMap);
			probabMap.put(neighbor, prob);
			sumInfor += prob;
		}
		
		//如果第一次走,信息素为0,则随机选择一个顶点
		if(Math.random() > 0.9){
			to = neighbors.get((int)(Math.random()*neighbors.size()));
		}else{
			for(int neighbor:neighbors){
				double p = probabMap.get(Integer.valueOf(neighbor))/sumInfor;
				if(Math.random() < p){
					to = neighbor;
					break;
				}
			}
			//若以上循环没有选出下一个节点,则选择最大信息素节点
			if(to == -1){
				double maxInfor = 0;
				for(int neighbor:neighbors){
					double probab = probabMap.get(Integer.valueOf(neighbor));
					if(maxInfor < probab){
						to = neighbor;
						maxInfor = probab;
					}
				}
			}
		}
		return to;
	}
	
	/**
	 * 如果邻居节点含有要求的点,则随机选择一个要求点
	 * @param neighbors
	 * @return
	 */
	public int hasCondition(List<Integer> neighbors){

		if(allConditionPoints && neighbors.contains(end)){
			return end;
		}
		
		List<Integer> conditionList = new ArrayList<Integer>();
		for(int i = 0;i < neighbors.size();i ++){
			int point = neighbors.get(i);
			if(checkCondiPoint(point)){
				conditionList.add(point);
			}
		}
		if(!conditionList.isEmpty()){
			return conditionList.get((int)(Math.random()*conditionList.size()));
		}
		return -1;
	}
	
	
	
	/**
	 * 蚂蚁不断移动,直到到达终点或无路可走
	 * 到达终点返回true,无路可走返回false
	 * @param updateCount
	 * @param sideMap
	 */
	public boolean moves(int updateCount,SideMap sideMap,double chooseRatio){
		//随机决定一种寻路方式
		boolean chooseMethod = (Math.random()>(1-chooseRatio));
		while(currentPoint != end){
			int next = -1;
			if(chooseMethod){
				//当chooseNextPoint返回-1表示无路可走
				chooseMethodFlag = false;
				next = chooseNextPoint(updateCount, sideMap);
			}else{
				chooseMethodFlag = true;
				next = chooseNextPoint(sideMap);
			}

			//如果还有路可以走
			if(next != -1){
				move(next, sideMap);
			}else{
				//无路可走
				return false;
			}
		}		
		return true;
	}
	/**
	 * 打印路径
	 * @return
	 */
	public static String printPath(List<Integer> path,SideMap sideMap){
		String str = ""+sideMap.getNum(path.get(0), path.get(1));
		for(int i = 1;i < path.size()-1;i ++){
			int num = sideMap.getNum(path.get(i), path.get(i + 1));
			str += "|"+num;
		}
		return str;
	}
}

package com.routesearch.route;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 蚁群算法搜索类
 * @author Hao
 *
 */
public class AntSearch {
	//蚂蚁数量
	private int antNum;
	//蚂蚁对象
	private Ant[] ants;
	//边集类
	private SideMap sideMap;
	//运行次数
	private int times;
	//用于限制迭代次数
	private int updateCount;
	//更新信息素需要的常量
	private static final double Q = 300;
	//挥发系数
	private double rou;
	//最佳路径长度
	private int bestPathLength;
	//最佳路径
	private List<Integer> bestPath;
	//最佳路径的边集
	protected static Set<Side> bestPathSide = new HashSet<Side>();
	//要求经过的顶点
	protected static List<Integer> conditionPoints;
	//提前结束条件,开始和结束点
	protected static boolean over;
	/**
	 * 构造函数
	 */
	public AntSearch(String graphContent,String condition,int antNum,int times,int updateCount){
		
		over = true;
		this.antNum = antNum;
		this.times = times;
		this.updateCount = updateCount;
		bestPathLength = Integer.MAX_VALUE;
		this.rou = 0.9;
		//解析条件字符串
		conditionPoints = parseCondition(condition);
		//声明sideMap对象
		sideMap = new SideMap(graphContent);
		//如果满足提前结束条件
		if(over){
			return;
		}
		//声明蚂蚁对象
		ants = new Ant[antNum];
		for(int i = 0;i < antNum;i ++){
			ants[i] = new Ant();
		}
		//声明最佳路径对象
		bestPath = new ArrayList<Integer>();
	}
	
	/**
	 * 解析条件字符串,设置Ant起点终点
	 * 返回必须经过的顶点
	 * @param condition
	 * @return
	 */
	public List<Integer> parseCondition(String condition){
		List<Integer> requirePoints = new ArrayList<Integer>();
		String[] data = condition.split(",");
		int start = Integer.parseInt(data[0]);
		int end = Integer.parseInt(data[1]);
		Ant.setStartEnd(start, end);
		//删除最后一个字符
		data[2] = data[2].substring(0, data[2].length() - 1);
		String[] points = data[2].split("\\|");
		for(String point:points){
			requirePoints.add(Integer.parseInt(point));
		}
		return requirePoints;
	}
	
	public String start(){
		//满足提前结束条件
		if(over){
			System.out.println("NA");
			return "NA";
		}
		//计时防止超出时间
		long startTime = System.currentTimeMillis();
		//初始挥发系数
		rou = 0.9;
		//方法选择率,用于蚂蚁选择节点的方法,0为环境素,1.0为信息素
		double chooseRatio = 0.0;
		//运行次数
		for(int runtimes = 0;runtimes < times;runtimes ++){
			
			//分别记录一次循环中最小路程和蚂蚁编号
			int tempPath = Integer.MAX_VALUE;
			int tempAnt = -1;
			//集合记录成功到达终点且通过检测的蚂蚁编号 
			List<Integer> antSucceed = new ArrayList<Integer>();
			//对于一个蚂蚁
			for(int i = 0;i < antNum;i++){
				Ant ant = ants[i];
				//如果能到达终点
				if(ant.moves(updateCount, sideMap,chooseRatio)){
				//	路径有效性:是否包含要求通过的顶点
					if(checkCondition(ant.getPath())){
						//记录该蚂蚁编号
						antSucceed.add(Integer.valueOf(i));
						if(ant.getPathLength() < tempPath){
							tempPath = ant.getPathLength();
							tempAnt = i;
						}
					}
				}
			}
			if(tempAnt != -1){
				updateInfor(tempAnt,1.0);				
			}
			//更新信息素
			updateInfor(antSucceed);
			
			//如果产生了更短的路径,则减慢信息素的挥发,获得更多的启发信息
			if(tempPath < bestPathLength){
				//对全局最优基于额外的奖励
				updateInfor(tempAnt, 2.0);
				
				Ant ant = ants[tempAnt];
				System.out.println();
				System.out.println("Time:"+(System.currentTimeMillis() - startTime)+"ms.");
				System.out.println("rou:"+rou);
				System.out.println("chooseRatio:"+ chooseRatio);
				System.out.println(ant.chooseMethodFlag?"conditInfor: ":"antInfro: ");
				updateCount = 0;
				bestPathLength = tempPath;
				bestPath = new ArrayList<Integer>(ant.getPath());
				bestPathSide.clear();
				for(int i = 0;i < bestPath.size()-1;i ++){
					bestPathSide.add(new Side(bestPath.get(i),bestPath.get(i + 1)));
				}
				//打桩
				System.out.println("bestPath at " + runtimes);
				System.out.println("bestPathLength - "+bestPathLength);
				System.out.println("Path: " + Ant.printPath(bestPath,sideMap));
				System.out.print("Points : ");
				for(int k = 0;k < bestPath.size();k ++){
					System.out.print(bestPath.get(k)+", ");
				}
				System.out.println();
//				System.out.println(sideMap.getInfors());
				chooseRatio = 0.9;
				rou = 0.9;
				
			}else{
				updateCount ++;
				chooseRatio -= 0.001;
				setRou(rou - 0.005);
			}
			
			//如果100代内都没有产生更好的路径,将信息素初始化
			if(updateCount > Ant.MAX_COUNT){
				//System.out.println("Update");
				sideMap.initInfor();
				chooseRatio=0.0;
				updateCount = 0;
			}
			
			//更新蚂蚁
			for(Ant ant:ants){
				ant.reset();
			}
			
			long endTime = System.currentTimeMillis();
			//如果时间不够,则返回退出
			if(endTime - startTime > 9.5*1000){
				System.out.println("EndTime:" + runtimes);
				return exit();
			}
		}
		return exit();
	}
	/**
	 * 结束方法,返回写入文件的字符串
	 * @return
	 */
	public String exit(){
		//如果最短距离没有改变
		if(bestPathLength == Integer.MAX_VALUE){
			System.out.println("NA");
			return "NA";
		}else{
			return Ant.printPath(bestPath,sideMap);
		}
	}
	
	/**
	 * 设置挥发系数,0.1-0.9限幅
	 * @param rou
	 */
	public void setRou(double rou) {
		if(rou > 0.9){
			this.rou = 0.9;
		}else if(rou < 0.1){
			this.rou = 0.1;
		}else{
			this.rou = rou;	
		}
	}
	/**
	 * 路径有效性检查,是否包含要求的全部顶点
	 * @param path
	 * @return
	 */
	public boolean checkCondition(List<Integer> path){
		return path.containsAll(conditionPoints);
	}
	
	/**
	 * 在tempAnt蚂蚁的路径上撒上信息素,强度为rate*Q
	 * @param tempAnt
	 * @param rate
	 */
	public void updateInfor(int tempAnt,double rate){
		Ant ant = ants[tempAnt];
		//取该蚂蚁路径
		List<Integer> path = ant.getPath();
		for(int j = 0;j < path.size() - 1;j ++){
			int from = path.get(j);
			int to = path.get(j + 1);
			double infor = sideMap.getInfor(from, to);
			//增加的信息量
			sideMap.setInfor(from, to, infor + Q*rate/ant.getPathLength());
		}
	}
	
	/**
	 * 更新信息素
	 * 只对成功到达且通过检测的蚂蚁更新
	 * @param antSucceed
	 */
	public void updateInfor(List<Integer> antSucceed){
		//对于通过检测的每一只蚂蚁
		for(int i = 0;i < antSucceed.size();i ++){
			updateInfor(antSucceed.get(i),0.1);
		}
		sideMap.volatilize(rou);
	}
	
}
/**
 * 实现代码文件
 * 
 * @author haor
 * @since 2016-3-25
 * @version V1.0
 */
package com.routesearch.route;

public final class Route
{
    /**
     * 你需要完成功能的入口
     * 
     * @author haor
     * @since 2016-3-25
     * @version V1
     */
    public static String searchRoute(String graphContent, String condition)
    {
//    	public AntSearch(String graphContent,String condition,int antNum,int times,int updateCount)
    	AntSearch search = new AntSearch(graphContent,condition,100,3000,0);
  
        return search.start();
    }

}

    原文作者:蚁群算法
    原文地址: https://blog.csdn.net/zhanghaor/article/details/51726579
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞