有個機器人坐在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)
相關文章
相關標籤/搜索