剑指 Offer 13. 机器人的运动范围
个人思路
思路
已经是二刷了,思路很清楚,也知道采用dfs,也知道如何进行深度优先搜索,但是对于dfs中何时需要标记数据,何时需要撤销操作还是有点雾水
对于此题来说,目标是要统计机器人能覆盖的格子数,而每次递归,递归体的for循环都是从0开始的,为了保证不重复访问那些已经访问过的格子,因此在dfs过程中不需要撤销操作,即不用对vis[tx][ty]进行撤销标记
对于求路径总条数、最短路径,dfs过程中都会探索出多条行走方式。因此存在这样的特殊场景:同一个点(并非终点,包括中间的点),可以有不同路径达到,只有进行撤销操作后,才能探索出多条完整的路径
for(int i = 0; i < 4; ++i){
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx >= 0 && tx < m && ty >= 0 && ty < n && (getNum(tx) + getNum(ty) <= k) && vis[tx][ty] == false){
cnt++;
dfs(m, n, k, tx, ty, cnt);
}
}
何时需要标记,何时需要撤销
- 有的(部分)路径需要你访问多次,这时候回溯需要取消标记,不然无法访问了;有的路径只访问一次,就不需要取消标记。
1.如果是visit[i]这种标记,回溯后i点应该视为没访问过,所以需要还原,不管是全局变量还是局部。
2.vector用来记录过程路径的,回溯后最后push的那个值就没有用的价值,所以要pop还原,不管是全局变量还是局部。
3.history[i]这种,用来记录第i点的值(颜色或者数字…),一般回溯到i之前的点时,第i点的取值就无所谓了,对dfs递归不影响,所以不用还原,还原也不会错。
4.int ans这种记录全局的变量,全局变量需要还原,局部不需要。
————————————————
版权声明:本文为CSDN博主「TodorovChen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/todorovchen/article/details/38534407
个人思路代码
class Solution {
public:
int dir[4][2] = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
bool vis[105][105];
int count = 1;
int getNum(int num){
int res = 0;
int temp;
while(num > 0){
temp = num % 10;
res += temp;
num /= 10;
}
return res;
}
int movingCount(int m, int n, int k) {
if(k == 0){
return count;
}
dfs(m, n, k, 0, 0, count);
return count;
}
void dfs(int m, int n, int k, int x, int y, int& cnt){
// cout << x << " " << y << " " << cnt << endl;
vis[x][y] = true;
for(int i = 0; i < 4; ++i){
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx >= 0 && tx < m && ty >= 0 && ty < n && (getNum(tx) + getNum(ty) <= k) && vis[tx][ty] == false){
cnt++;
dfs(m, n, k, tx, ty, cnt);
}
}
}
};