Saturday, August 2, 2014

Robot in grid - unique paths

Problem

A robot is located at the top-left corner of a NXN grid. The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid. How many possible unique paths are there?

Approach

UniquePaths(row, column) = 0 if row > N or column > N
                                                1 if row ==N and column == N
                                                 UniquePaths(row+1, column) + UniquePaths(row, column+1)


i.e, the recursive method has optimal substructure and overlapping sub problems. So, the problem can be solved using Dynamic Programming.
Code Snippet
  1. private int GetNumberOfUniquePaths(int row, int column, int N)
  2.         {
  3.             if ((row == N) && (column == N))
  4.             {
  5.                 return 1;
  6.             }
  7.             if ((row > N) || (column > N))
  8.             {
  9.                 return 0;
  10.             }
  11.             int uniquePathsByMovingDown = this.GetNumberOfUniquePaths(row + 1, column, N);
  12.             int uniquePathsByMovingRight = this.GetNumberOfUniquePaths(row, column + 1, N);
  13.             return uniquePathsByMovingDown + uniquePathsByMovingRight;
  14.         }
  15.         int GetNumberOfUniquePaths(int N)
  16.         {
  17.             int r = this.GetNumberOfUniquePaths(1, 1, N);
  18.             return r;
  19.         }

DP - Memoization (Top-Down - Lazy)

Code Snippet
  1. int GetUniquePaths_DP_Memoization_Lazy(int N)
  2.         {
  3.             int?[][] DP_Memoization_Lazy_Cache = new int?[N + 1][];
  4.             for(int i =0;i<=N;i++)
  5.             {
  6.                 DP_Memoization_Lazy_Cache[i] = new int?[N + 1];
  7.                 for(int j=0;j<=N;j++)
  8.                 {
  9.                     DP_Memoization_Lazy_Cache[i][j] = null;
  10.                 }
  11.             }
  12.             this.GetUniquePaths_DP_Memoization_Lazy(DP_Memoization_Lazy_Cache, row: 1, column: 1);
  13.             return DP_Memoization_Lazy_Cache[1][1].Value;
  14.         }
  15.         private int GetUniquePaths_DP_Memoization_Lazy(int?[][] DP_Memoization_Lazy_Cache, int row,
  16.             int column)
  17.         {
  18.             int N = DP_Memoization_Lazy_Cache.Length - 1;
  19.             if (row > N)
  20.             {
  21.                 return 0;
  22.             }
  23.             if (column > N)
  24.             {
  25.                 return 0;
  26.             }
  27.             if(DP_Memoization_Lazy_Cache[row][column] != null)
  28.             {
  29.                 return DP_Memoization_Lazy_Cache[row][column].Value;
  30.             }
  31.             if((row == N) && (column == N))
  32.             {
  33.                 DP_Memoization_Lazy_Cache[N][N] = 1;
  34.                 return 1;
  35.             }
  36.             int pathsWhenMovedDown = this.GetUniquePaths_DP_Memoization_Lazy(DP_Memoization_Lazy_Cache,
  37.                 row + 1, column);
  38.             int pathsWhenMovedRight = this.GetUniquePaths_DP_Memoization_Lazy(DP_Memoization_Lazy_Cache,
  39.                 row, column + 1);
  40.             DP_Memoization_Lazy_Cache[row][column] = pathsWhenMovedDown + pathsWhenMovedRight;
  41.             return DP_Memoization_Lazy_Cache[row][column].Value;
  42.         }

Getting Paths

Code Snippet
  1. Tuple<int, int>[][] GetUniquePaths(int N)
  2.         {
  3.             var r = this.GetUniquePaths(1, 1, N);
  4.             return r;
  5.         }
  6.         private Tuple<int, int>[][] GetUniquePaths(int row, int column, int N)
  7.         {
  8.             if ((row == N) && (column == N))
  9.             {
  10.                 var r = new Tuple<int, int>[1][];
  11.                 r[0] = new Tuple<int, int>[] { new Tuple<int,int>(row, column) };
  12.                 return r;
  13.             }
  14.             if ((row > N) || (column > N))
  15.             {
  16.                 return new Tuple<int, int>[0][];
  17.             }
  18.             var uniquePathsByMovingDown = this.GetUniquePaths(row + 1, column, N);
  19.             var uniquePathsByMovingRight = this.GetUniquePaths(row, column + 1, N);
  20.             List<Tuple<int, int>[]> paths = this.MergePaths(uniquePathsByMovingDown,
  21.                 row, column).ToList();
  22.             paths.AddRange(this.MergePaths(uniquePathsByMovingRight, row, column));
  23.             return paths.ToArray();
  24.         }
  25.         private Tuple<int, int>[][] MergePaths(Tuple<int, int>[][] paths,
  26.             int row, int column)
  27.         {
  28.             Tuple<int, int>[][] mergedPaths = new Tuple<int, int>[paths.Length][];
  29.             if (paths.Length > 0)
  30.             {
  31.                 Assert.IsTrue(paths.All(p => p.Length > 0));
  32.                 for (int i = 0; i < paths.Length; i++)
  33.                 {
  34.                     List<Tuple<int, int>> mergedPath = new List<Tuple<int, int>>();
  35.                     mergedPath.Add(new Tuple<int, int>(row, column));
  36.                     mergedPath.AddRange(paths[i]);
  37.                     mergedPaths[i] = mergedPath.ToArray();
  38.                 }
  39.             }
  40.             return mergedPaths;
  41.         }

DP - Bottom-Up

Code Snippet
  1. int DP_BottomUp_GetNumberOfUniquePaths(int N)
  2.         {
  3.             int[][] DP_BottomUp_Tabular_Eager_Cache = new int[N + 1][];
  4.             for (int row = 0; row <= N; row++)
  5.             {
  6.                 DP_BottomUp_Tabular_Eager_Cache[row] = new int[N + 1];
  7.                 for (int column = 0; column <= N; column++)
  8.                 {
  9.                     if ((row == N)
  10.                         || (column == N))
  11.                     {
  12.                         DP_BottomUp_Tabular_Eager_Cache[row][column] = 1;
  13.                     }
  14.                 }
  15.             }
  16.             for (int row = N - 1; row >= 1;row--)
  17.             {
  18.                 for (int column = N - 1; column >= 1; column--)
  19.                 {
  20.                     DP_BottomUp_Tabular_Eager_Cache[row][column] =
  21.                         DP_BottomUp_Tabular_Eager_Cache[row + 1][column]
  22.                         + DP_BottomUp_Tabular_Eager_Cache[row][column + 1];
  23.                 }
  24.             }
  25.             return DP_BottomUp_Tabular_Eager_Cache[1][1];
  26.         }

Unit Tests

Code Snippet
  1. [TestMethod]
  2.         [TestCategory(Constants.DynamicProgramming)]
  3.         public void RobotInGridTests()
  4.         {
  5.             int p = this.DP_BottomUp_GetNumberOfUniquePaths(3);
  6.             Assert.AreEqual(p, 6);
  7.             p = GetNumberOfUniquePaths(3);
  8.             Assert.AreEqual(p, 6);
  9.             int p1 = this.GetUniquePaths_DP_Memoization_Lazy(3);
  10.             Assert.AreEqual(p, p1);
  11.             var p2 = this.GetUniquePaths(3);
  12.             Assert.AreEqual(p1, p2.Length);
  13.             foreach (var path in p2)
  14.             {
  15.                 Debug.WriteLine("===================================================================");
  16.                 foreach (Tuple<int, int> t in path)
  17.                 {
  18.                     Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
  19.                 }
  20.             }
  21.             p = this.DP_BottomUp_GetNumberOfUniquePaths(4);
  22.             Assert.AreEqual(p, 20);
  23.             p = GetNumberOfUniquePaths(4);
  24.             Assert.AreEqual(p, 20);
  25.             p1 = this.GetUniquePaths_DP_Memoization_Lazy(4);
  26.             Assert.AreEqual(p, p1);
  27.             p2 = this.GetUniquePaths(4);
  28.             Assert.AreEqual(p1, p2.Length);
  29.             foreach (var path in p2)
  30.             {
  31.                 Debug.WriteLine("===================================================================");
  32.                 foreach (Tuple<int, int> t in path)
  33.                 {
  34.                     Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
  35.                 }
  36.             }
  37.         }

Finding the number of paths mathematically

Say, if the grid is 4X4 => i.e, the number of unique paths is nothing but all possible permutations of RRRDDD where R represents right and D represents Down. For details, please see the attached image:



Related Links

No comments:

Post a Comment