这道题学到了在做回溯时,先把点加入到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;
}
}