题目:
地上有一个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个格子。
按照代码中规定的“右下左上”的试探顺序,可以画图如下: