Algorithm for finding all paths in a NxN grid

前端 未结 10 1315
忘了有多久
忘了有多久 2020-11-28 08:27

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 ro

相关标签:
10条回答
  • 2020-11-28 08:57

    Scenario:
    1. Imagine there is NxN zero indexed matrix.
    2. Initial position of robot is upper-left corner i.e. (N-1, N-1)
    3. Robot wants to reach lower right corner i.e. at (0,0)

    Solution:
    -- In any possible solution robot will move N rights steps and N down steps to reach (0,0), or we can say that initial robot has permission to move N rights steps and N down steps.
    -- When ever robot moves right we reduce its remaining number of right steps by 1, same is for down movement.
    -- At every position(except at boundary, where it will have only one option) robot have two options, one is it can go down or other is it can go right.
    -- It will terminate when robot will have no remaining down of right steps.

    **Below code also have driver method main(), you can change the value of N. N can be >=1

    public class RobotPaths {
    
    public static int robotPaths(int down, int right, String path)
    {
        path = path+ down +","+ right +"  ";
        if(down==0 && right==0)
        {
            System.out.println(path);
            return 1;
        }
    
        int counter = 0;
    
        if(down==0)
            counter = robotPaths(down, right-1, path);
        else if(right==0)
            counter = robotPaths(down-1, right, path);
        else
            counter = robotPaths(down, right-1, path) + robotPaths(down-1, right, path);
    
        return counter;
    }
    
    public static void main(String[] args) 
    {
        int N = 1;
        System.out.println("Total possible paths: "+RobotPaths.robotPaths(N-1, N-1, ""));
    
    }
    

    }

    0 讨论(0)
  • 2020-11-28 08:59

    Here is c# version (just for reference) to find unique paths (note here is the version which returns number of paths using dynamic programming (memorization - lazy) - Calculating number of moves from top left corner to bottom right with move in any direction) (you may refer to my blog for more details: http://codingworkout.blogspot.com/2014/08/robot-in-grid-unique-paths.html)

    Tuple<int, int>[][] GetUniquePaths(int N)
            {
                var r = this.GetUniquePaths(1, 1, N);
                return r;
            }
            private Tuple<int, int>[][] GetUniquePaths(int row, int column, int N)
            {
                if ((row == N) && (column == N))
                {
                    var r = new Tuple<int, int>[1][];
                    r[0] = new Tuple<int, int>[] { new Tuple<int,int>(row, column) };
                    return r;
                }
                if ((row > N) || (column > N))
                {
                    return new Tuple<int, int>[0][];
                }
                var uniquePathsByMovingDown = this.GetUniquePaths(row + 1, column, N);
                var uniquePathsByMovingRight = this.GetUniquePaths(row, column + 1, N);
                List<Tuple<int, int>[]> paths = this.MergePaths(uniquePathsByMovingDown,
                    row, column).ToList();
                paths.AddRange(this.MergePaths(uniquePathsByMovingRight, row, column));
                return paths.ToArray();
            }
    

    where

    private Tuple<int, int>[][] MergePaths(Tuple<int, int>[][] paths, 
                int row, int column)
            {
                Tuple<int, int>[][] mergedPaths = new Tuple<int, int>[paths.Length][];
                if (paths.Length > 0)
                {
                    Assert.IsTrue(paths.All(p => p.Length > 0));
                    for (int i = 0; i < paths.Length; i++)
                    {
                        List<Tuple<int, int>> mergedPath = new List<Tuple<int, int>>();
                        mergedPath.Add(new Tuple<int, int>(row, column));
                        mergedPath.AddRange(paths[i]);
                        mergedPaths[i] = mergedPath.ToArray();
                    }
                }
                return mergedPaths;
            }
    

    Unit Tests

    [TestCategory(Constants.DynamicProgramming)]
            public void RobotInGridTests()
            {
                int p = this.GetNumberOfUniquePaths(3);
                Assert.AreEqual(p, 6);
                int p1 = this.GetUniquePaths_DP_Memoization_Lazy(3);
                Assert.AreEqual(p, p1);
                var p2 = this.GetUniquePaths(3);
                Assert.AreEqual(p1, p2.Length);
                foreach (var path in p2)
                {
                    Debug.WriteLine("===================================================================");
                    foreach (Tuple<int, int> t in path)
                    {
                        Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
                    }
                }
                p = this.GetNumberOfUniquePaths(4);
                Assert.AreEqual(p, 20);
                p1 = this.GetUniquePaths_DP_Memoization_Lazy(4);
                Assert.AreEqual(p, p1);
                p2 = this.GetUniquePaths(4);
                Assert.AreEqual(p1, p2.Length);
                foreach (var path in p2)
                {
                    Debug.WriteLine("===================================================================");
                    foreach (Tuple<int, int> t in path)
                    {
                        Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
                    }
                }
            }
    
    0 讨论(0)
  • 2020-11-28 09:00
    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);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 09:03

    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
    
    0 讨论(0)
提交回复
热议问题