題目:
地上有一個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個格子。
按照代碼中規定的“右下左上”的試探順序,可以畫圖如下: