机器人的运动范围(深度优先遍历与广度优先遍历)

地上有一个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

 

解题思路:深度优先遍历

可以从左上角(0,0)开始向下与向右进行深度优先遍历,如果k很小,则在整个二维数组中,机器人可以运动的范围将被分割成几个不连通的部分,但随着k增大,逐渐开始连通,也是从机器人的右边和下边首先开始连通的,所以只用递归下下边和右边就行了。用深度优先遍历从(0,0)开始往右边或下边搜索到底,再返回上一个元素往另一个方向搜索,以此类推。

 

算法流程:

public:

1.创建标记二维数组flag标记已经走过的位置,并初始化为0

2.返回深度优先遍历函数dfs的返回值

传入(第一个位置的行数0,列数0,flag数组,地图行数m,地图列数n,k)

 

private:

1.定义dfs函数,传入(当前位置的函数 i,当前位置的列数 j,flag,m,n,k)

               如果i>=m(越界)或j>=n(越界)或 i 的个位数+ i 十位数+ j 的个位数+ j的十位数 > k 或flag[i][j]==true(走过了)

                       返回0

               flag[i][j]=1(标记走过的位置为true)

               返回 1+递归向下搜索+递归向右搜索

 

代码:

class Solution {

public:

    int movingCount(int m, int n, int k) {

    vector<vector<bool>> flag(m,vector<bool> (n,0));

    return dfs(0,0,flag,m,n,k);

    }

    

private:

    int dfs(int i,int j,

vector<vector<bool>> &flag,int m,int n,int k) {

    if(i>=m||j>=n||i%10+i/10+j%10+j/10>k||

flag[i][j]) return 0;

   flag[i][j]=true;

   return 1+dfs(i+1,j,flag,m,n,k)+

          dfs(i,j+1,flag,m,n,k);

}

 

};

 

 

解题思路:广度优先遍历

也可以用广度优先遍历从(0,0)开始,把其右边的位置(0,1)与其下边的位置(1,0)入队q,然后(0,0)出队。再队头元素(0,1)出队,再把其右边与下边的位置入队,以此类推。直到队列为空,则说明搜索结束。为了避免重复走过,也需flag标记函数。队列q需要存储位置,所以需要创建数组类型的队列。最后还要一个计数变量count统计可以运动到的位置的数目。

 

算法流程:

1.创建标记二维数组flag并初始化为0

2.创建数组类型的队列q

3.创建计数遍历count并初始化为0

4.把第一个位置[0,0]入队

5.循环直到队列为空

               创建数组arr存储队头元素

               队头元素出队

               创建遍历 i 存储位置的行数

               创建遍历 j 存储位置的列数

               创建遍历 a 存储行数的个位数与十位数之和

               创建遍历 b 存储列数的个位数与十位数之和

               如果行数或列数越界或a+b > k 或flag已走过

                       跳过本次循环执行下一个循环

               count++

               标记该位置为true

               该位置的下边位置入队

               该位置的右边位置入队

6.返回count

 

代码:

class Solution {

public:

    int movingCount(int m, int n, int k) {

    vector<vector<bool>> flag(m,vector<bool> (n,0));

    queue<vector<int>> q;

    int count=0; 

    q.push({0,0});

    while(!q.empty()) {

        vector<int> arr=q.front();

        q.pop();

        int i=arr[0],j=arr[1];

        int a=i%10+i/10;

        int b=j%10+j/10;

        if(i>=m||j>=n||a+b>k||flag[i][j])

        continue;

        count++;

        flag[i][j]=true;

        q.push({i+1,j});

        q.push({i,j+1});

    }

    return count;

    }

};

        

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于问题,我可以帮你解答,但是我不是一个可以执行代码的机器人,只能提供思路和算法。 1. 建立有向图的邻接矩阵和邻接表存储结构: 邻接矩阵存储结构: 对于有 N 个顶点的图,邻接矩阵是一个 N*N 的矩阵,其中第 i 行第 j 列的值表示从顶点 i 到顶点 j 是否有一条边。如果有,则为 1,否则为 0。 对于该图,邻接矩阵如下: ``` 0 1 2 3 4 5 6 0 0 1 0 0 1 1 0 1 0 0 0 1 0 1 1 2 0 0 0 0 1 0 1 3 0 0 1 0 0 0 1 4 0 0 0 0 0 0 1 5 0 0 0 0 0 0 1 6 0 0 0 0 0 0 0 ``` 邻接表存储结构: 对于有 N 个顶点的图,邻接表是一个长度为 N 的数组,每个数组元素对应一个顶点,每个元素是一个链表,链表中存储从该顶点出发的所有边所连接的顶点。 对于该图,邻接表如下: ``` 0 -> 1 -> 4 -> 5 1 -> 3 -> 5 -> 6 2 -> 4 -> 6 3 -> 2 -> 6 4 -> 6 5 -> 6 6 -> ``` 2. 根据邻接表,实现图G的从顶点0开始的深度优先广度优先运算: 深度优先深度优先使用栈来实现。首先将起点入栈,然后弹出栈顶元素,访问该元素,并将其未被访问过的邻居入栈,直到栈为空。 ``` void dfs(int start, vector<vector<int>>& graph, vector<bool>& visited) { stack<int> st; st.push(start); visited[start] = true; while (!st.empty()) { int cur = st.top(); st.pop(); cout << cur << " "; for (int neighbor : graph[cur]) { if (!visited[neighbor]) { visited[neighbor] = true; st.push(neighbor); } } } } ``` 广度优先广度优先使用队列来实现。首先将起点入队,然后弹出队头元素,访问该元素,并将其未被访问过的邻居入队,直到队列为空。 ``` void bfs(int start, vector<vector<int>>& graph, vector<bool>& visited) { queue<int> q; q.push(start); visited[start] = true; while (!q.empty()) { int cur = q.front(); q.pop(); cout << cur << " "; for (int neighbor : graph[cur]) { if (!visited[neighbor]) { visited[neighbor] = true; q.push(neighbor); } } } } ``` 3. 根据邻接表,实现图G的从顶点0开始的深度优先生成树和广度优先生成树: 深度优先生成树: 深度优先生成树使用递归来实现。从起点开始,依次访问与其相邻的未被访问过的顶点,对于每个未被访问过的顶点,将其标记为已访问,并将其加入到该顶点的子树中。 ``` void dfs_tree(int cur, vector<vector<int>>& graph, vector<bool>& visited, vector<int>& parent) { visited[cur] = true; for (int neighbor : graph[cur]) { if (!visited[neighbor]) { parent[neighbor] = cur; dfs_tree(neighbor, graph, visited, parent); } } } ``` 广度优先生成树: 广度优先生成树使用队列来实现。从起点开始,依次访问与其相邻的未被访问过的顶点,对于每个未被访问过的顶点,将其标记为已访问,并将其加入到该顶点的子树中。 ``` void bfs_tree(int start, vector<vector<int>>& graph, vector<bool>& visited, vector<int>& parent) { queue<int> q; q.push(start); visited[start] = true; while (!q.empty()) { int cur = q.front(); q.pop(); for (int neighbor : graph[cur]) { if (!visited[neighbor]) { visited[neighbor] = true; parent[neighbor] = cur; q.push(neighbor); } } } } ``` 4. 输出从顶点5到顶点2的所有长度为3的简单路径和最短路径: 简单路径: 使用深度优先搜索,记录搜索路径,每次搜索到终点时判断路径长度是否为 3,如果是,则输出路径。 ``` void dfs_path(int cur, int dest, int len, vector<vector<int>>& graph, vector<bool>& visited, vector<int>& path) { visited[cur] = true; path.push_back(cur); if (cur == dest && len == 3) { for (int v : path) { cout << v << " "; } cout << endl; } else { for (int neighbor : graph[cur]) { if (!visited[neighbor]) { dfs_path(neighbor, dest, len+1, graph, visited, path); } } } path.pop_back(); visited[cur] = false; } ``` 最短路径: 使用广度优先搜索,记录每个节点的距离和前驱节点,直到搜索到终点,根据前驱节点回溯输出路径。 ``` void bfs_shortest_path(int start, int dest, vector<vector<int>>& graph, vector<int>& distance, vector<int>& parent) { queue<int> q; q.push(start); distance[start] = 0; parent[start] = -1; while (!q.empty()) { int cur = q.front(); q.pop(); if (cur == dest) { break; } for (int neighbor : graph[cur]) { if (distance[neighbor] == -1) { distance[neighbor] = distance[cur] + 1; parent[neighbor] = cur; q.push(neighbor); } } } if (distance[dest] == -1) { cout << "No path exists!" << endl; } else { cout << "Shortest path: "; vector<int> path; for (int cur = dest; cur != -1; cur = parent[cur]) { path.push_back(cur); } reverse(path.begin(), path.end()); for (int v : path) { cout << v << " "; } cout << endl; } } ``` 5. 销毁图G的邻接表: 遍邻接表中的每个链表,释放链表中每个节点的内存,在释放链表的头节点的内存。最后将邻接表的指针置为 nullptr。 ``` void destroy_graph(vector<vector<int>*>& graph) { for (vector<int>* list : graph) { delete list; } graph.clear(); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值