a*

a*算法是搜索最短路径的算法(曼哈顿距离)。

你要记住一个公式 F=G(从起点到该放个的当前最小消耗)+H(预估到终点距离)

整个搜索过程中有:

graph[][]搜索地图, used搜索过的节点集合,waiting 等待搜索的节点集合。

起始点 start,终点 end

1:将 start 放入 waiting

2:从 waiting 中取出 F 最小并且不在 used 中的节点为当前节点 now,将 now 放入 used。

3:遍历 now 周边联通、不再 used 中的节点 around。

如果没在 waiting 中:将 around 的父节点设置为 now,然后将 around 加入 waiting 中。

如果存在 waiting 中:如果 around 的 G 值更高:什么都不作,如果 around.G 低将 waiting[around].G = around.G 并重新计算 F waiting[around].parrent = around。

4:循环 2,3 直到 end 添加到 used 中。

5:路径即 end.parent 这条链路。

	public static int MAX_X = 10;
	
	public static int MAX_Y = 10;
	
	static class Node{
		int x;// 点的位置X
		int y;// 点的位置Y
		int F;// F = G + H
		int G;// 从起点到该点的最小消耗
		int H;// 预估到终点的距离
		Node parent;
		public void countH(Node to){
			int disX = to.x - this.x;
			int disY = to.y - this.y;
			this.H = Math.abs(disX) + Math.abs(disY);
		}
		public void countF(){
			this.F = this.G + this.H;
		}
		public Node up(Node to){
			return nextNode(0, -1, to);
		}
		public Node down(Node to){
			return nextNode(0, 1, to);
		}
		public Node left(Node to){
			return nextNode(-1, 0, to);
		}
		public Node right(Node to){
			return nextNode(1, 0, to);
		}
		public Node nextNode(int incrementX, int incrementY, Node to){
			Node node = new Node();
			node.x = this.x + incrementX;
			node.y = this.y + incrementY;
			node.G = this.G + 1;
			node.countH(to);
			node.countF();
			node.parent = this;
			return node;
		}
	}
	
	/**
	 * node是否在图内
	 * @param node
	 * @param maxX
	 * @param maxY
	 * @return
	 */
	private static boolean inRange(Node node, int maxX, int maxY){
		return node.x >= 0 && node.x <= maxX && node.y >= 0 && node.y <= maxY;
	}
	
	/**
	 * 是否x,y坐标相等
	 * @param node
	 * @param node2
	 * @return
	 */
	private static boolean equals(Node node, Node node2){
		return node != null && node2 != null && node.x == node2.x && node.y == node2.y;
	}
	
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		Scanner scan = new Scanner(System.in);
		int[][] graph = InputUtils.getGraph();
		MAX_X = MAX_Y = graph.length - 1;
		LOG.d("to index:x y");
		Node to = new Node();
		to.x = scan.nextInt();
		to.y = scan.nextInt();
		LOG.d("from index:x y");
		Node from = new Node();
		from.x = scan.nextInt();
		from.y = scan.nextInt();
		from.countH(to);
		axing(graph, from, to);
	}
	
	public static void axing(int[][] graph, Node from, Node to){
		List<Node> waiting = new ArrayList<>();
		List<Node> used = new ArrayList<>();
		waiting.add(from);
		while (waiting.size() > 0){
			Node min = findMinWithF(waiting, used);
			used.add(min);
			if (equals(min, to)){
				printLine(min);
				printLineGraph(graph, min);
				break;
			}
			addAroundToWaiting(graph, waiting, used, min, to);
		}
	}
	
	private static void printLineGraph(int[][] graph, Node end){
		while (end != null){
			graph[end.y][end.x] = 3;
			end = end.parent;
		}
		printGraph(graph);
	}
	
	private static void printGraph(int[][] graph){
		for (int i = 0; i < graph.length; i++){
			for (int j = 0; j < graph[i].length; j++){
				if (graph[i][j] == 1){
					System.out.print("_ ");
				} else if (graph[i][j] == 3){
					System.out.print("* ");
				} else {
					System.out.print("X ");
				}
			}
			System.out.println();
		}
	}
	
	private static void printLine(Node end){
		while (end != null){
			LOG.d("short line:(", end.x, ",", end.y, ")");
			end = end.parent;
		}
	}
	
	/**
	 * 添加到等待开启列表
	 * @param waiting
	 * @param used
	 * @param node
	 */
	private static void addToWaiting(int[][] graph, List<Node> waiting, List<Node> used, Node node){
		if (!inRange(node, MAX_X, MAX_Y)){
			return;
		}
		if (graph[node.y][node.x] == 0){
			return;
		}
		if (inUsed(used, node)){
			return;
		}
		if (!changeInWaiting(waiting, node)){
			waiting.add(node);
		}
	}
	
	/**
	 * 是否在关闭列表中
	 * @param used
	 * @param node
	 * @return
	 */
	private static boolean inUsed(List<Node> used, Node node){
		return findInList(used, node) != null;
	}
	
	/**
	 * 是否在列表中存在
	 * @param list
	 * @param node
	 * @return
	 */
	private static Node findInList(List<Node> list, Node node){
		for (Node n : list){
			if (equals(n, node)){
				return n;
			}
		}
		return null;
	}
	
	/**
	 * 在开启列表中修改G值
	 * @param waiting
	 * @param node
	 * @return 修改成功返回 true 失败返回 false
	 */
	private static boolean changeInWaiting(List<Node> waiting, Node node){
		for (Node n : waiting){
			if (equals(n, node)){
				if (n.G > node.G){
					n.parent = node.parent;
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * 获取列表中F最小的点
	 * @param waiting
	 * @return
	 */
	private static Node findMinWithF(List<Node> waiting, List<Node> used){
		Node min = null;
		int minIndex = -1;
		for (int i = 0; i < waiting.size(); i++){
			if (!inUsed(used, waiting.get(i))){
				if (min == null || min.F > waiting.get(i).F){
					minIndex = i;
					min = waiting.get(i);
				}
			}
		}
		if (minIndex != -1)
			waiting.remove(minIndex);
		return min;
	}
	
	/**
	 * 添加周边点进入等待开启列表
	 * @param waiting
	 * @param used
	 * @param node
	 * @param to
	 */
	private static void addAroundToWaiting(int[][] graph, List<Node> waiting, List<Node> used, Node node, Node to){
		Node up = node.up(to);
		addToWaiting(graph, waiting, used, up);
		Node down = node.down(to);
		addToWaiting(graph, waiting, used, down);
		Node left = node.left(to);
		addToWaiting(graph, waiting, used, left);
		Node right = node.right(to);
		addToWaiting(graph, waiting, used, right);
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值