有个机器人坐在X*Y网格的左上角,只能向右、向下移动,机器人从(0,0)到(X,Y)有多少种走法

/**
 * 功能:有个机器人坐在X*Y网格的左上角,只能向右、向下移动。机器人从(0,0)到(X,Y)有多少种走法。
 * 进阶:假设有些点为“禁区”,机器人不能踏足。找出一条路径,让机器人从左上角移动到右下角。java

 */算法

 

解答:数组

排列组合问题:共有(X+Y)!/X!Y!缓存

 

进阶问题有两种方法:app

 

方法一:this

[java] view plain copyspa

 

  1. //递归法  
  2. /** 
  3.  * 思路:自上而下 
  4.  * 从终点往回走,试着找出到其相邻点的路径。 
  5.  * @param x 
  6.  * @param y 
  7.  * @param path 
  8.  * @return 
  9.  */  
  10. public static boolean getPath(int x,int y,ArrayList<Point> path){  
  11.     Point p=new Point(x,y);  
  12.     path.add(p);  
  13.     if(x==0&&y==0)  
  14.         return true;//找到路径  
  15.       
  16.     boolean success=false;  
  17.     if(x>=1&&isFree(x-1,y))//向左走  
  18.         success=getPath(x-1,y, path);  
  19.     if(y>=1&&isFree(x,y-1))  
  20.         success=getPath(x,y-1,path);  
  21.       
  22.     if(!success)  
  23.         path.add(p);//错误路径  
  24.        
  25.     return success;  
  26.       
  27. }  


 

 

方法二:.net

 

[java] view plain copy设计

 

  1. <span style="white-space:pre">    </span>//动态规划  
  2.     /** 
  3.      * 思路:缓存先前访问过的点 
  4.      * @param x 
  5.      * @param y 
  6.      * @param path 
  7.      * @param cache 
  8.      * @return 
  9.      */  
  10.     public static boolean getPathDP(int x,int y,ArrayList<Point> path,HashMap<Point,Boolean> cache){  
  11.         Point p=new Point(x,y);  
  12.         if(x==0&y==0)  
  13.             return true;  
  14.           
  15.         path.add(p);  
  16.           
  17.         if(cache.containsKey(p))  
  18.             return cache.get(p);  
  19.           
  20.         boolean success=false;  
  21.         if(x>=1&&isFree(x-1,y))  
  22.             success=getPathDP(x-1, y, path, cache);  
  23.         if(y>=1&&isFree(x,y-1))  
  24.             success=getPathDP(x, y-1, path, cache);  
  25.           
  26.         if(!success)  
  27.             path.add(p);//错误路径的点  
  28.           
  29.         cache.put(p, success);//缓存结果  
  30.           
  31.         return success;  
  32.     }  
  33. }  
  34.   
  35. class Point{  
  36.     int x;  
  37.     int y;  
  38.     boolean isFree;  
  39.       
  40.     public Point(){}  
  41.     public Point(int x,int y){  
  42.         this.x=x;  
  43.         this.y=y;  
  44.     }  
  45. }

1、无障碍的网格code

问题描述:

  有一个XxY的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角。请设计一个算法,计算机器人有多少种走法。给定两个正整数int x,int y表示网格的大小,计算机器人的走法数目。

求解思路:

  对于本题,咱们依然运用动态规划的思想。对于网格中的每个格子,若该格子位于第一行,则只能由左边的格子到达;若格子位于第一列,只 能由上面的格子到达;网格中的其余格子能够由左边的格子到达,也能够由上面的格子到达。所以到达每个格子的方法数都由左边的或者上面的格子所决定。咱们 依次从网格的左上角遍历到右下角,则到达右下角格子的方法数即是最终的结果了。

代码实现:

 

[java] view plain copy

 

  1. import java.util.Scanner;  
  2. import java.util.Stack;  
  3. public class Main {  
  4.     public static void main(String[] args) {  
  5.         Scanner sc=new Scanner(System.in);  
  6.         int x=sc.nextInt();  
  7.         int y=sc.nextInt();  
  8.         if(x==0||y==0)   
  9.             System.out.println(0);  
  10.         else if(x==1||y==1)  
  11.             System.out.println(1);  
  12.         else{  
  13.             int [][]f=new int[x][y];  
  14.             for(int j=0;j<y;j++){  
  15.                 f[0][j]=1;  
  16.             }  
  17.             for(int i=0;i<x;i++){  
  18.                 f[i][0]=1;  
  19.             }  
  20.             for(int i=1;i<x;i++){  
  21.                 for(int j=1;j<y;j++){  
  22.                     f[i][j]=f[i][j-1]+f[i-1][j];  
  23.                 }  
  24.             }  
  25.             System.out.println(f[x-1][y-1]);  
  26.         }  
  27.     }  
  28. }  

2、有障碍的网格

 

问题描述:

 题目与上述相似,只是注意此次的网格中有些障碍点是不能走的,给定一个int[][]map表示网格图,若map[i][j]为0则说明该点不是障碍点,不然为障碍点。计算机器人从(0,0)走到(x - 1,y - 1)的走法数。

求解思路:

  求解思路也与上题相似,只是此时网格中有障碍点,咱们能够这样考虑:

(1)当格子是障碍点时,机器人不能达到此格点,方法数为0;

(2)当格子不是障碍点时,则说明机器人向右走或向下走能到达此格子,所以到达此格子的方法数为到达其上方格子和左边格子的方法数之和。
代码实现:

 

[java] view plain copy

 

  1. public int countWays(int[][] map, int x, int y) {  
  2.         int step[][]=new int[x][y];  
  3.         if(map[0][0]==0) step[0][0]=1;  
  4.         else step[0][0]=0;  
  5.         for(int j=1;j<y;j++){  
  6.             if(map[0][j]==0)  
  7.                 step[0][j]=step[0][j-1];  
  8.             else  
  9.                 step[0][j]=0;  
  10.         }  
  11.         for(int i=1;i<x;i++){  
  12.             if(map[i][0]==0)  
  13.                 step[i][0]=step[i-1][0];  
  14.             else  
  15.                 step[i][0]=0;  
  16.         }  
  17.         for(int i=1;i<x;i++){  
  18.             for(int j=1;j<y;j++){  
  19.                 if(map[i][j]==0)  
  20.                     step[i][j]=step[i][j-1]+step[i-1][j];  
  21.                 else  
  22.                     step[i][j]=0;  
  23.             }  
  24.         }  
  25.         return step[x-1][y-1];  
  26.     } 
  27.  

在一个N*N矩阵的左上角坐着一个机器人,它只能向右运动或向下运动。那么, 机器人运动到右下角一共有多少种可能的路径?

进一步地,

若是对于其中的一些格子,机器人是不能踏上去的。设计一种算法来得到全部可能的路径。

解答

为了通常化这个问题,咱们假设这个矩阵是m*n的,左上角的格子是(1, 1), 右下角的坐标是(m, n)。

解法一

这个题目能够递归来解,如何递归呢?首先,咱们须要一个递推公式, 对于矩阵中的格子(i, j),假设从(1, 1)到它的路径数量为path(i, j), 那么,有:

path(i, j) = path(i-1, j) + path(i, j-1)

很好理解,由于机器人只能向右或向下运动,所以它只能是从(i-1, j)或(i, j-1) 运动到(i, j)的,因此路径数量也就是到达这两个格子的路径数量之和。而后, 咱们须要一个初始条件,也就是递归终止条件,是什么呢?能够发现, 当机器人在第一行时,不论它在第一行哪一个位置,从(1, 1)到达那个位置都只有一条路径, 那就是一路向右;同理,当机器人在第一列时,也只有一条路径到达它所在位置。 有了初始条件和递推公式,咱们就能够写代码了,以下:

ll path(ll m, ll n){
    if(m == 1 || n == 1) return 1;
    else return path(m-1, n) + path(m, n-1);
}

ll是数据类型long long。

解法二

若是用纯数学的方法来解这道题目,大概也就是个高中排列组合简单题吧。 机器人从(1, 1)走到(m, n)必定要向下走m-1次,向右走n-1次,无论这过程当中是怎么走的。 所以,一共可能的路径数量就是从总的步数(m-1+n-1)里取出(m-1)步,做为向下走的步子, 剩余的(n-1)步做为向右走的步子。

C(m-1+n-1, m-1)=(m-1+n-1)! / ( (m-1)! * (n-1)! )

代码以下:

ll fact(ll n){
    if(n == 0) return 1;
    else return n*fact(n-1);
}
ll path1(ll m, ll n){
    return fact(m-1+n-1)/(fact(m-1)*fact(n-1));
}

对于第二问,若是有一些格子,机器人是不能踏上去的(好比说放了地雷XD), 那么,咱们如何输出它全部可能的路径呢?

让咱们先来考虑简单一点的问题,若是咱们只要输出它其中一条可行的路径便可, 那么咱们能够从终点(m, n)开始回溯,遇到可走的格子就入栈, 若是没有格子能到达当前格子,当前格子则出栈。最后到达(1, 1)时, 栈中正好保存了一条可行路径。代码以下:

bool get_path(int m, int n){
    point p; p.x=n; p.y=m;
    sp.push(p);
    if(n==1 && m==1) return true;
    bool suc = false;
    if(m>1 && g[m-1][n])
        suc = get_path(m-1, n);
    if(!suc && n>1 && g[m][n-1])
        suc = get_path(m, n-1);
    if(!suc) sp.pop();
    return suc;
}

其中二维数组g表示的是M*N的矩阵,元素为1表示该位置能够走,为0表示该位置不可走。 这个只能获得其中一条可行路径,但题目是要求咱们找到全部可行路径,并输出。 这样的话,又该怎么办呢?咱们从(1, 1)开始,若是某个格子能够走, 咱们就将它保存到路径数组中;若是不能走,则回溯到上一个格子, 继续选择向右或者向下走。当机器人走到右下角的格子(M, N)时,便可输出一条路径。 而后程序会退出递归,回到上一个格子,找寻下一条可行路径。代码以下:

void print_paths(int m, int n, int M, int N, int len){
    if(g[m][n] == 0) return;
    point p; p.x=n; p.y=m;
    vp[len++] = p;
    if(m == M && n == N){
        for(int i=0; i<len; ++i)
            cout<<"("<<vp[i].y<<", "<<vp[i].x<<")"<<" ";
        cout<<endl;
    }
    else{
        print_paths(m, n+1, M, N, len);
        print_paths(m+1, n, M, N, len);
    }
}

程序使用的输入样例8.2.in以下:

3 4
1 1 1 0
0 1 1 1
1 1 1 1

输出路径以下:

one of the paths:
(1, 1) (1, 2) (1, 3) (2, 3) (2, 4) (3, 4) 
all paths:
(1, 1) (1, 2) (1, 3) (2, 3) (2, 4) (3, 4) 
(1, 1) (1, 2) (1, 3) (2, 3) (3, 3) (3, 4) 
(1, 1) (1, 2) (2, 2) (2, 3) (2, 4) (3, 4) 
(1, 1) (1, 2) (2, 2) (2, 3) (3, 3) (3, 4) 
(1, 1) (1, 2) (2, 2) (3, 2) (3, 3) (3, 4)
相关文章
相关标签/搜索