想象一下,机器人坐在NxN网格的左上角。机器人只能向两个方向移动:向右和向下。机器人有多少可能的路径?
我可以在Google上找到解决此问题的方法,但我对解释并不十分清楚。我试图清楚地理解如何解决这个问题并在Java中实现的逻辑。任何帮助表示赞赏。
更新:这是一个面试问题。现在,我正试图到达右下角并打印可能的路径。
答案 0 :(得分:32)
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);
}
查找所有可能的路径:
仍然使用递归方法。路径变量在开头分配“”,然后将访问的每个点添加到“路径”。到达(n,n)点时形成可能的路径,然后将其添加到列表中。
每条路径表示为字符串,例如“(1,1)(2,1)(3,1)(4,1)(4,2)(4,3)(4,4)”。所有可能的路径都存储在字符串列表中。
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);
}
}
答案 1 :(得分:18)
我认为你的问题没有障碍迹象,所以我们可以假设没有。
请注意,对于n + 1乘n + 1网格,机器人需要准确执行2n
步才能到达右下角。因此,它不能超过2n
次移动。
让我们从一个更简单的案例开始: [找到右下角的所有路径]
机器人可以准确地制作choose(n,2n)
= (2n)!/(n!*n!)
条道路:它只需要选择哪个2n
移动是正确的,其余的是向下移动(确切地说{{1} }} 这些)。
生成可能的路径:只生成大小为n
的所有二进制向量,其中2n
为1。 1表示右移,0表示向下移动。
现在,让我们将其扩展到所有路径:
首先选择路径的长度。为此,请迭代所有可能性:n
,其中0 <= i <= 2n
是路径的长度。在此路径中,有i
个正确的步骤。
要生成所有可能性,请实现以下伪代码:
max(0,i-n) <= j <= min(i,n)
注1:打印大小为i的所有二进制向量,j位设置为1,计算成本可能很高。这是预期的,因为存在指数数量的解决方案。
注2:对于案例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
,您可以按预期获得i=2n
(上述更简单的情况)。
答案 2 :(得分:2)
https://math.stackexchange.com/questions/104032/finding-points-in-a-grid-with-exactly-k-paths-to-them - 看看我的解决方案。似乎它正是你所需要的(是的,陈述略有不同,但一般情况下它们只是一样)。
答案 3 :(得分:1)
这适用于机器人可以使用4个方向而不仅仅是2个方向,但下面的递归解决方案(在Javascript中)可行并且我已尽力使其尽可能清晰:
//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;
};
清洁版:
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;
}
所以:
robotPaths(5); //returns 8512
答案 4 :(得分:0)
方案:
1.想象一下,有NxN零索引矩阵
2.机器人的初始位置是左上角,即(N-1,N-1)
机器人想要到达右下角,即(0,0)
解决方案:
- 在任何可能的解决方案中,机器人将移动N个权限步骤和N个向下步骤以达到(0,0),或者我们可以说初始机器人有权移动N个权限步骤和N个向下步骤。
- 当机器人向右移动时,我们将其剩余的右步数减少1,同样是向下移动
- 在每个位置(除边界外,它只有一个选项)机器人有两个选项,一个是可以下降,另一个是可以向右。
- 当机器人没有正确的步骤时,它将终止。
**下面的代码也有驱动程序方法main(),你可以改变N的值.N可以是&gt; = 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, ""));
}
}
答案 5 :(得分:0)
这是c#版本(仅供参考)以查找唯一路径(请注意这里是使用动态编程返回路径数的版本(记忆 - 懒惰) - Calculating number of moves from top left corner to bottom right with move in any direction)(您可以参考我的博客更多详情: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();
}
其中
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;
}
单元测试
[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));
}
}
}
答案 6 :(得分:0)
这是一个适用于矩形和方形网格的完整实现。我会告诉你如何处理多余的“=&gt;”在每条路径的尽头。
(some-test)
答案 7 :(得分:0)
如果您只需要计算有效路径:
假设你有一个矩阵n * m矩阵,你将所有单元格设置为零,并且&#34; offlimit&#34;细胞到-1。
然后,您可以使用动态编程解决问题:
// a is a matrix with 0s and -1s
// n, m are the dimensions
// M is 10^9-7 incase you have a large matrix
if (a[0][0] == 0) a[0][0] = 1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == -1) continue;
if (i > 0) a[i][j] = (a[i][j] + max(a[i-1][j], 0LL)) % M;
if (j > 0) a[i][j] = (a[i][j] + max(a[i][j-1], 0LL)) % M;
}
}
// answer at lower right corner
cout << a[n-1][m-1];
没有递归或膨胀的数据结构,速度极快。
注意:这是因为重复而被删除但由于这是此主题的最佳主题,我已从其他地方删除了我的答案,并将在此处添加。
答案 8 :(得分:0)
下面是Java中的代码,用于计算NXN矩阵左上角到右下角的所有可能路径。
public class paths_in_matrix {
/**
* @param args
*/
static int n=5;
private boolean[][] board=new boolean[n][n];
int numPaths=0;
paths_in_matrix(){
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
board[i][j]=false;
}
}
}
private void togglePiece(int i,int j){
this.board[i][j]=!this.board[i][j];
}
private boolean hasBeenVisited(int i,int j){
return this.board[i][j];
}
private boolean exists(int i,int j){
return i < n && i > -1 && j < n && j > -1;
}
private boolean viablePosition(int i,int j){
return exists(i, j) && !hasBeenVisited(i,j);
}
private void traversePaths(int i,int j){
//BASE CASE: if reached (n - 1, n - 1), count as path and stop.
if (i == (n - 1) && j == (n - 1)) {
this.numPaths++;
return;
}
this.togglePiece(i, j);
//RECURSIVE CASE: if next point is a viable position, go there and make the same decision
//go right if possible
if (this.viablePosition(i, j + 1)) {
traversePaths(i, j + 1);
}
//go left if possible
if (this.viablePosition(i, j - 1)) {
traversePaths( i, j - 1);
}
//go down if possible
if (this.viablePosition(i + 1, j)) {
traversePaths( i + 1, j);
}
//go up if possible
if (this.viablePosition(i - 1, j)) {
traversePaths(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
this.togglePiece(i, j);
}
private int robotPaths(){
traversePaths(0,0);
return this.numPaths;
}
public static void main(String[] args) {
paths_in_matrix mat=new paths_in_matrix();
System.out.println(mat.robotPaths());
}
}
答案 9 :(得分:-2)
int N;
function num_paths(intx,int y)
{
int[][] arr = new int[N][N];
arr[N-1][N-1] = 0;
for(int i =0;i<N;i++)
{
arr[N-1][i]=1;
arr[i][N-1]=1;
}
for(int i = N-2;i>=0;i--)
{
for(int j=N-2;j>=0;j--)
{
arr[i][j]= arr[i+1][j]+arr[i][j+1];
}
}
return arr[0][0];
}