Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithm for finding all paths in a NxN grid

Tags:

java

algorithm

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. How many possible paths are there for the robot?

I could find solution to this problem on Google, but I am not very clear with the explanations. I am trying to clearly understand the logic on how to solve this and implement in Java. Any help is appreciated.

Update: This is an interview question. For now, I am trying to reach the bottom-right end and print the possible paths.

like image 808
Periastron Avatar asked Feb 02 '12 00:02

Periastron


People also ask

How many paths does an 8x8 grid have?

We can conclude that there are 6 distinct paths in this grid. Now take a look at this 8x8 grid: If you try to count the number of paths on this grid, if will take you quite some time. We will need some more intelligent, mathematical approach.

How many paths does a 4x4 grid have?

For a 4x4 grid I need to make 6 moves. There are 64 possible paths.

How many paths does a 2x2 grid have?

Starting in the top left corner of a 2 × 2 grid, there are 6 routes (without backtracking) to the bottom right corner.


4 Answers

public static int computePaths(int n){     return recursive(n, 1, 1);       }     public static int recursive(int n, int i, int j){     if( i == n || j == n){         //reach either border, only one path         return 1;     }     return recursive(n, i + 1, j) + recursive(n, i, j + 1); } 

To find all possible paths:
still using a recursive method. A path variable is assigned "" in the beginning, then add each point visited to 'path'. A possible path is formed when reaching the (n,n) point, then add it to the list.

Each path is denoted as a string, such as " (1,1) (2,1) (3,1) (4,1) (4,2) (4,3) (4,4)". All possible paths are stored in a string list.

public static List<String> robotPaths(int n){     List<String> pathList = new ArrayList<String>();     getPaths(n, 1,1, "", pathList);     return pathList; } public static void getPaths(int n, int i, int j, String path, List<String> pathList){     path += String.format(" (%d,%d)", i , j);     if( i ==n && j == n){ //reach the (n,n) point         pathList.add(path);     }else if( i > n || j > n){//wrong way         return;     }else {         getPaths(n, i +1, j , path, pathList);         getPaths(n, i , j +1, path, pathList);     } } 
like image 175
Ethan Avatar answered Sep 24 '22 22:09

Ethan


I see no indications for obstacles in your question so we can assume there are none.

Note that for an n+1 by n+1 grid, a robot needs to take exactly 2n steps in order to reach the lower right corner. Thus, it cannot make any more than 2n moves.

Let's start with a simpler case: [find all paths to the right down corner]

The robot can make exactly choose(n,2n)= (2n)!/(n!*n!) paths: It only needs to choose which of the 2n moves will be right, with the rest being down (there are exactly n of these).
To generate the possible paths: just generate all binary vectors of size 2n with exactly n 1's. The 1's indicate right moves, the 0's, down moves.

Now, let's expand it to all paths:
First choose the length of the path. To do so, iterate over all possibilities: 0 <= i <= 2n, where i is the length of the path. In this path there are max(0,i-n) <= j <= min(i,n) right steps.
To generate all possibilities, implement the following pseudo-code:

for each i in [0,2n]:   for each j in [max(0,i-n),min(i,n)]:     print all binary vectors of size i with exactly j bits set to 1 

Note 1: printing all binary vectors of size i with j bits set to 1 could be computationally expensive. That is expected since there are an exponential number of solutions.
Note 2: For the case i=2n, you get j in [n,n], as expected (the simpler case described above).

like image 32
amit Avatar answered Sep 21 '22 22:09

amit


https://math.stackexchange.com/questions/104032/finding-points-in-a-grid-with-exactly-k-paths-to-them - look here at my solution. Seems that it is exactly what you need (yes, statements are slightly different, but in general case they are just the same).

like image 44
OleGG Avatar answered Sep 25 '22 22:09

OleGG


This is for if the robot can go 4 directions rather than just 2, but the recursive solution below (in Javascript) works and I've tried to make it as legible as possible:

//first make a function to create the board as an array of arrays
var makeBoard = function(n) {
  var board = [];
  for (var i = 0; i < n; i++) {
    board.push([]);
    for (var j = 0; j < n; j++) {
      board[i].push(false);
    }
  }
  board.togglePiece = function(i, j) {
    this[i][j] = !this[i][j];
  }
  board.hasBeenVisited = function(i, j) {
    return !!this[i][j];
  }
  board.exists = function(i, j) {
    return i < n && i > -1 && j < n && j > -1;
  }
  board.viablePosition = function(i, j) {
    return board.exists(i, j) && !board.hasBeenVisited(i,j);
  }
  return board;
};


var robotPaths = function(n) {
  var numPaths = 0;
  //call our recursive function (defined below) with a blank board of nxn, with the starting position as (0, 0)
  traversePaths(makeBoard(n), 0, 0);

  //define the recursive function we'll use
  function traversePaths(board, i, j) {
    //BASE CASE: if reached (n - 1, n - 1), count as solution and stop doing work
    if (i === (n - 1) && j === (n - 1)) {
      numPaths++;
      return;
    }
    //mark the current position as having been visited. Doing this after the check for BASE CASE because you don't want to turn the target position (i.e. when you've found a solution) to true or else future paths will see it as an unviable position
    board.togglePiece(i, j);

    //RECURSIVE CASE: if next point is a viable position, go there and make the same decision

    //go right if possible
    if (board.viablePosition(i, j + 1)) {
      traversePaths(board, i, j + 1);
    }

    //go left if possible
    if (board.viablePosition(i, j - 1)) {
      traversePaths(board, i, j - 1);
    }

    //go down if possible
    if (board.viablePosition(i + 1, j)) {
      traversePaths(board, i + 1, j);
    }

    //go up if possible
    if (board.viablePosition(i - 1, j)) {
      traversePaths(board, i - 1, j);
    }

    //reset the board back to the way you found it after you've gone forward so that other paths can see it as a viable position for their routes
    board.togglePiece(i, j);
  }
  return numPaths;
};

A cleaner version:

var robotPaths = function(n, board, i, j) {
    board = board || makeBoard(n),
    i = i || 0,
    j = j || 0;

    // If current cell has been visited on this path or doesn't exist, can't go there, so do nothing (no need to return since there are no more recursive calls below this)
    if (!board.viablePosition(i, j)) return 0;
    // If reached the end, add to numPaths and stop recursing
    if (i === (n - 1) && j === (n - 1)) return 1;
    // Mark current cell as having been visited for this path
    board.togglePiece(i, j);
    // Check each of the four possible directions
    var numPaths = robotPaths(n, board, i + 1, j) + robotPaths(n, board, i - 1, j) + robotPaths(n, board, i, j + 1) + robotPaths(n, board, i, j - 1);
    // Reset current cell so other paths can go there (since board is a pointer to an array that every path is accessing)
    board.togglePiece(i, j);
    return numPaths;
}

So:

robotPaths(5); //returns 8512
like image 31
Muhammad Naqvi Avatar answered Sep 21 '22 22:09

Muhammad Naqvi