机器人的运动范围

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入:m = 2, n = 3, k = 1
输出:3

示例 2:

输入:m = 3, n = 1, k = 0
输出:1

提示:

  • 1 <= n,m <= 100
  • 0 <= k <= 20

思路一:

dfs,深度优先遍历每一个格子,如果当前格子满足条件,则计数加1。运动的过程中,可以只考虑向下和向右,因为向上的格子,要么被向下方向走过,要么会被向右方向走过。向右同理。所以只需要考虑向下和向右。

代码

class Solution {
private:
    int ans = 0;
    vector<vector<int>> visited;
public:
    int getDigits(int x) {
        int a = 0;
        while (x > 0) {
            a += x%10;
            x /= 10;
        }
        return a;
    }
    void dfs(int m,int n,int i,int j,int k) {
        if (i>=0 && i < m && j >= 0 && j < n && getDigits(i)+getDigits(j)<=k && visited[i][j] == false) {
            //当前位置满足条件,计数加一,并且记录,防止重复计算。
            ans++;
            visited[i][j] = true;
            vector<vector<int>> directions = {{0,1},{1,0}};
            for(const auto& dir: directions) {
                int newI = i+dir[0];
                int newJ = j+dir[1];
                dfs(m, n, newI, newJ, k);
            }
        }
    }
    int movingCount(int m, int n, int k) {
        ans = 0;
        visited.resize(m, vector<int>(n));
        dfs(m, n, 0, 0,k);
        return ans;
    }
};

思路2:

bfs,广度遍历每一个格子,统计满足条件的格子个数。因为只考虑向左和向下,所以其实整个遍历路径就是一棵二叉树。可以使用二叉树的层序遍历方法。

class Solution {
public:
    int getDigitsSum(int x) {
        int ans = 0;
        while(x > 0) {
            ans += x%10;
            x /= 10;
        }
        return ans;
    }
    int movingCount(int m, int n, int k) {
        if(k < 0 || m <= 0 || n <= 0) {
            return 0;
        }
        queue<pair<int,int>> que;
        que.push({0,0});
        int ans = 1;
        vector<pair<int,int>> directions{{0,1},{1,0}};
        vector<vector<bool>> visited(m,vector<bool>(n));
        visited[0][0] = true;
        while(!que.empty()) {
            auto p = que.front();
            que.pop();
            for(const auto& direction: directions) {
                int newRow = direction.first + p.first;
                int newCol = direction.second + p.second;
                if(newRow >= 0&& newRow < m&& newCol >= 0&& newCol < n && getDigitsSum(newRow)+getDigitsSum(newCol) <= k && !visited[newRow][newCol]) {
                    ans++;
                    que.push({newRow,newCol});
                    visited[newRow][newCol] = true;
                }
            }
        }
        return ans;
    }
};

思路3:

动态规划。记dp[i][j],表示机器人能否进入位置(i,j),如果i和j的数位之和小于等于k,而机器人从(i-1,j)或者(i,j-1)位置移动而来,如果i == 0,j==0,则dp[i][j] = true,如果i!=0,j==0则dp[i][j] = dp[i-1][j],如果i==0,j!=0则dp[i][j] = dp[i][j-1],如果i!=0,j!=0,则dp[i][j]=dp[i-1][j] | dp[i][j-1]。如果dp[i][j]==true,则格子数加1

代码:

class Solution {
public:
    int getDigitsSum(int x) {
        int ans = 0;
        while(x > 0) {
            ans += x%10;
            x /= 10;
        }
        return ans;
    }
    int movingCount(int m, int n, int k) {
        if(k < 0 || m <= 0 || n <= 0) {
            return 0;
        }
        vector<vector<bool>> memery(m,vector<bool>(n));
        int ans = 0;
        for(int i = 0;i < m;i++) {
            for(int j = 0;j < n;j++) {
                if(getDigitsSum(i)+getDigitsSum(j) <= k) {
                    if(i == 0 && j == 0) {
                        memery[i][j] = true;
                    }
                    else if(i > 0 && j == 0) {
                        memery[i][j] = memery[i-1][j];
                    }
                    else if(j > 0 && i == 0) {
                        memery[i][j] = memery[i][j-1];
                    }
                    else {
                        memery[i][j] = memery[i-1][j] | memery[i][j-1];
                    }
                    ans += memery[i][j];
                }
            }
        } 
        return ans;
    }
};