Recursion 二维空间里机器人向右或向下走的所有路径问题 @CareerCup

这篇博客探讨了在二维空间中,机器人只能向右或向下移动的所有可能路径问题。通过回溯算法,博主强调在处理路径时,应当先将当前点加入路径,再根据子情况判断是否需要保留该点。同时比较了自己的解决方案与官方答案,认为自己的方法在判断自由移动点上更为直观。

这道题学到了在做回溯时,先把点加入到path中,然后根据子情况来决定success这个变量,从而决定之前加入的点是否有必要的。如果子情况返回的是false,则这个点也没有必要加入到path中,就可以移除了。

还有一个是,我的解答中每次函数只对当前点进行isFree的判断,官方答案中却对下一个节点进行判断。我还是觉得我的更直观一些。


package Recursion;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Hashtable;

import CtCILibrary.AssortedMethods;

/**
 * Imagine a robot sitting on the upper left comer of an X by Ygrid. The robot
 * can only move in two directions: right and down. How many possible paths are
 * there for the robot to go from (0, 0) to (X, Y) ?
 * 
 * 在一个N*N矩阵的左上角坐着一个机器人,它只能向右运动或向下运动。那么, 机器人运动到右下角一共有多少种可能的路径?
进一步地,如果对于其中的一些格子,机器人是不能踏上去的。设计一种算法来获得所有可能的路径。
 * 
 */
public class S9_2 {

	public static int[][] maze = new int[10][10];
	
	public static void main(String[] args) {
		maze = AssortedMethods.randomMatrix(10, 10, 0, 4);
		AssortedMethods.printMatrix(maze);
		ArrayList<Point> path = new ArrayList<Point>();
		boolean success = getPathRec(9, 9, path);
		ArrayList<Point> pathRef = new ArrayList<Point>();
		boolean successRef = getPathRef(9, 9, pathRef);
		Hashtable<Point, Boolean> cache = new Hashtable<Point, Boolean>();
		ArrayList<Point> pathDP = new ArrayList<Point>();
		getPathMemo(9, 9, pathDP, cache);
		if (success) {
			String s = AssortedMethods.listOfPointsToString(path);
			System.out.println(s);
			System.out.println(AssortedMethods.listOfPointsToString(pathRef));
			System.out.println(AssortedMethods.listOfPointsToString(pathDP));
		} else {
			System.out.println("No path found.");
		}
	}
	
	// 返回是否成功获得一条路径
	public static boolean getPathRec(int x, int y, ArrayList<Point> path) {
		
		boolean free = isFree(x, y);		// 检查是否当前位置是合法的
		boolean success = false;			// 表示成功获得路径
		path.add(new Point(x, y));		// 可以采用先加入,如果后面的success为false则移除的方法!
		
		if(x==0 && y==0 && free){			// 到达初始点,找到路径
			return true;
		}
		
		if(x == 0 && free){					// 第一行
			success = getPathRec(x, y-1, path);
		}
		
		if(y == 0 && free){					// 第一列
			success = getPathRec(x-1, y, path);
		}
		
		if(x>0 && y>0 && free){			// 中间位置
			success = getPathRec(x-1, y, path);		// 先尝试往上走
			if( !success ){									// 如果往上走不得再尝试往左走
				success = getPathRec(x, y-1, path);
			}
		}
		
		if(!success){				// 如果所有尝试都失败了,证明当前节点不适合,因此移除!
			path.remove(path.size()-1);
		}
		return success;
	}
	
	public static boolean getPathMemo(int x, int y, ArrayList<Point> path, Hashtable<Point, Boolean> ht) {
		boolean free = isFree(x, y);		// 检查是否当前位置是合法的
		boolean success = false;			// 表示成功获得路径
		path.add(new Point(x, y));		// 可以采用先加入,如果后面的success为false则移除的方法!
		
		Point p = new Point(x, y);
		if(ht.contains(p)){					// 利用cache预先判断
			return ht.get(p);
		}
		
		if(x==0 && y==0 && free){			// 到达初始点,找到路径
			return true;
		}
		
		if(x == 0 && free){					// 第一行
			success = getPathMemo(x, y-1, path, ht);
		}
		
		if(y == 0 && free){					// 第一列
			success = getPathMemo(x-1, y, path, ht);
		}
		
		if(x>0 && y>0 && free){			// 中间位置
			success = getPathMemo(x-1, y, path, ht);		// 先尝试往上走
			if( !success ){									// 如果往上走不得再尝试往左走
				success = getPathMemo(x, y-1, path, ht);
			}
		}
		
		if(!success){				// 如果所有尝试都失败了,证明当前节点不适合,因此移除!
			path.remove(path.size()-1);
		}
		return success;
	}
	
	public static boolean isFree(int x, int y){
		return maze[x][y] != 0;
	}
	
	
	// 官方答案
	public static boolean getPathRef(int x, int y, ArrayList<Point> path) {
		Point p = new Point(x, y);
		path.add(p);
		if (x == 0 && y == 0) {
			return true; // found a path
		}
		boolean success = false;
		if (x >= 1 && isFree(x - 1, y)) { // Try right
			success = getPathRef(x - 1, y, path); // Free!  Go right
		}
		if (!success && y >= 1 && isFree(x, y - 1)) { // Try down
			success = getPathRef(x, y - 1, path); // Free!  Go down
		}
		if (!success) {
			path.remove(p); // Wrong way! Better stop going this way
		}
		return success;
	}

}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值