all possible paths for the robot

时间:2015-10-06 08:46:30

标签: java algorithm recursion

Imagine a robot sitting on the upper left hand corner of an NxN grid. The robot can only move in two directions: right and down. Imagine certain squares are “off limits”, such that the robot can not step on them. Design an algorithm to get all possible paths for the robot.

Here is the reference implementation I got, I think the implementation is wrong since it only find one path, other than all possible paths (more details, in line 10, the robot only goes down if no valid path in right. But to find all possible paths, the robot should try both right and down)? Want to confirm my understanding is correct.

ArrayList<Point> current_path = new ArrayList<Point>();
public static boolean getPaths(int x, int y) {
      Point p = new Point(x, y);
      current_path.add(p);
      if (0 == x && 0 == y) return true; // current_path
      boolean success = false;
      if (x >= 1 && is_free(x - 1, y)) { // Try right
        success = getPaths(x - 1, y); // Free! Go right
      }
      if (!success && y >= 1 && is_free(x, y - 1)) { // Try down
        success = getPaths(x, y - 1); // Free! Go down
      }
      if (!success) {
        current_path.remove(p); // Wrong way!
      }
      return success;
}

thanks in advance, Lin

2 个答案:

答案 0 :(得分:2)

以下是您可以做的事情:

public  static class Point {
    int x, y;
    public Point (int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return String.format("[%d, %d]", x, y);
    }
}

public static void getPathsRec(int x, int y, Deque<Point> currentPath,
                               List<List<Point>> paths) {
    if (x == 0 && y == 0) {
        List<Point> path = new ArrayList<Point>();
        for (Point p : currentPath)
            path.add(p);
        paths.add(path);
        //System.out.println(currentPath);
        return;
    }

    if (x > 0 && is_free(x-1, y)) {
        currentPath.push(new Point(x-1, y));
        getPathsRec(x-1, y, currentPath, paths);
        currentPath.pop();
    }

    if (y > 0 && is_free(x, y-1)) {
        currentPath.push(new Point(x, y-1));
        getPathsRec(x, y-1, currentPath, paths);
        currentPath.pop();
    }
}

static int n = 2;
public static List<List<Point>> getPaths() {
    List<List<Point>> paths = new ArrayList<List<Point>>();
    Deque<Point> d = new ArrayDeque<Point>();
    d.push(new Point(n-1, n-1));
    getPathsRec(n - 1, n - 1, d, paths);
    //System.out.println(paths);
    return paths;
}

这是一个简单的backtracking。我们的想法是以递归方式访问下一个状态,但要确保在调用之后状态返回到之前的状态(就像在调用之前一样)。这是通过弹出Deque中的元素来完成的。

请注意,为简单起见,您可以引入新的类Path,类似于:

class Path {
    List<Point> points;
}

使代码更具可读性。然后getPaths()会返回List<Path>,这会更好。

另请考虑重新定义getPathsRec以获得签名getPathsRec(Point p, Deque<Point>, List<Path> ),即拥有一个参数Point而不是x, y。考虑到您已定义x, y这一事实,class Point似乎是多余的。这将使它看起来更好。

答案 1 :(得分:1)

您的解决方案有误,因为一旦达到(0 == x && y==0)success值将始终设置为true。因此,它不会进入后期if

以下是您的问题的示例答案。它使用回溯算法:

public class test {
    static int n = 3; //substitute your n value here
    static ArrayList<Point> current_path = new ArrayList<Point>();
    static boolean[][] blockedCell = new boolean[n][n];
    public static void FindAllWay(int x, int y)
    {
        if (x <0 || y < 0) return;
        Point p = new Point(x, y);
        current_path.add(p);

        if (0 == x && 0 == y){
            System.out.println(current_path.toString());
            current_path.remove(current_path.size()-1);
            return;
        }

        if ((x > 0) && !blockedCell[x-1][y]) //go right
        {
            blockedCell[x-1][y] = true;
            FindAllWay(x-1, y);
            blockedCell[x-1][y] = false;
        }
        if ((y > 0) &&!blockedCell[x][y-1]) // go down
        {
            blockedCell[x][y-1] = true;
            FindAllWay(x, y-1);
            blockedCell[x][y-1] = false;
        }
        current_path.remove(current_path.size()-1);

    }

    public static void main(String[] args)
    {
        FindAllWay(n-1,n-1);
    }
}