編程題:機器人的運動範圍

題目:

地上有一個m行和n列的方格。一個機器人從座標(0,0)的格子開始移動,每一次只能向左,右,上,下四個方向中其中一個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?

輸入示例:

m=5, n=5, k=6

輸出示例:

22

規定:

需要注意是橫縱座標的數位之和,不是直接求和。

解題思路:

思路:

本題採用“回溯法”進行求解,關於回溯法的介紹和應用可以翻閱此處
需要注意的除了數位和的限制外,還要注意題目所求是“機器人能夠達到多少個格子”,仔細分析是要求這個機器人最多可以到達多少個格子,而非最深路徑能夠到達多少個格子。

代碼:

class Solution {
public:
    bool shuweihe(int row, int col, int threshold){
        //判斷數位和是否在閾值內
        int i = 0, j=0;
        while(row!=0){
            i += row%10;
            row = row/10;
        }
        while(col!=0){
            j += col%10;
            col = col/10;
        }
        if(i+j<=threshold){
            return true;
        }
        else{
            return false;
        }
    }
    
    void backtracking(vector<vector<int>> &used, int i, int j, int threshold, 
                     int rows, int cols, int &cnt){
        //cnt計數,max真正的最大值
        if(i<0||j<0||i>rows||j>cols){
            return;
        }
        
        if(shuweihe(i,j,threshold)){
            //數位和在閾值內
            cnt++;
            used[i][j]=1;
            //右下左上
            if(j+1<cols && used[i][j+1]!=1){
                backtracking(used, i, j+1, threshold, rows, cols, cnt);
            }
            if(i+1<rows && used[i+1][j]!=1){
                backtracking(used, i+1, j, threshold, rows, cols, cnt);
            }
            if(j-1>=0 && used[i][j-1]!=1){
                backtracking(used, i, j-1, threshold, rows, cols, cnt);
            }
            if(i-1>=0 && used[i-1][j]!=1){
                backtracking(used, i-1, j, threshold, rows, cols, cnt);
            }
            // used[i][j]=0;//無需重置,走過的已經被計數了,不再走
            return;
        }
        else{
            return;
        }
    }
    
    int movingCount(int threshold, int rows, int cols)
    {
        vector<vector<int>> used(rows, vector<int> (cols));
        if(rows<0 || cols<0){
            return 0;
        }
        int cnt=0;
        backtracking(used, 0, 0, threshold, rows, cols, cnt);
        return cnt;
    }
};

完整程序:

#include <iostream>
#include <vector>
using namespace std;

//code block,上述代碼塊,填充至此。

int main(){
    int rows=5, cols=5, threshold=6;
    Solution so;
    int result = so.movingCount(threshold, rows, cols);
    cout<< result<< endl;
    return 0;
}

輸入輸出測試:

測試用例1:

輸入:
5, 5, 6
輸出:
22

測試用例2:

輸入:
5,10,10
輸出:
21

測試用例3:

輸入:
15,20,20
輸出:
359

進一步思考:

本題是要求這個機器人最多可以到達多少個格子。那如果進一步考慮,要求最深路徑能夠到達多少個格子呢?應該怎麼求解?
可以想到,需要在上述函數中添加最大值max記錄,記錄每次機器人走完一條路徑後到達格子數的最大值。但是可以想到的是,如果這個二維矩陣過大且給的閾值過大,那麼機器人可以走的路徑是非常多的,在一定時間內幾乎無法遍歷完,因此下述代碼只是對此問題給個初步解答,實際上只能求解矩陣較小或者閾值較小的情況。

class Solution {
public:
    bool shuweihe(int row, int col, int threshold){
        //判斷數位和是否在閾值內
        int i = 0, j=0;
        while(row!=0){
            i += row%10;
            row = row/10;
        }
        while(col!=0){
            j += col%10;
            col = col/10;
        }
        if(i+j<=threshold){
            return true;
        }
        else{
            return false;
        }
    }
    
    int backtracking(vector<vector<int>> &used, int i, int j, int threshold, 
                     int rows, int cols, int &cnt, int &max){
        //cnt計數,max真正的最大值
        if(i<0||j<0||i>rows||j>cols){
            return max;
        }
        
        if(shuweihe(i,j,threshold)){
            //數位和在閾值內
            cnt++;
            used[i][j]=1;
            //右下左上
            if(j+1<cols && used[i][j+1]!=1){
                max = backtracking(used, i, j+1, threshold, rows, cols, cnt, max);
            }
            if(i+1<rows && used[i+1][j]!=1){
                max = backtracking(used, i+1, j, threshold, rows, cols, cnt, max);
            }
            if(j-1>=0 && used[i][j-1]!=1){
                max = backtracking(used, i, j-1, threshold, rows, cols, cnt, max);
            }
            if(i-1>=0 && used[i-1][j]!=1){
                max = backtracking(used, i-1, j, threshold, rows, cols, cnt, max);
            }
            used[i][j]=0;//重置
            if(cnt>max){
                max = cnt;
            }
            cnt--;
            return max;
        }
        else{
            if(cnt>max){
                max = cnt;
            }
            return max;//時刻保證return的是最大值
        }
    }
    
    int movingCount(int threshold, int rows, int cols)
    {
        vector<vector<int>> used(rows, vector<int> (cols));
        if(rows<0 || cols<0){
            return 0;
        }
        int cnt=0, max =0;
        max = backtracking(used, 0, 0, threshold, rows, cols, cnt, max);
        return max;
    }
};

對此問題的測試用例:
輸入:
5, 5, 6
輸出:
21

注意兩個問題的區別:在5,5,6的輸入下,這個機器人最多可以到達22個格子,單次最深路徑能夠到達21個格子。
按照代碼中規定的“右下左上”的試探順序,可以畫圖如下:
畫圖對比

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章