最短路径||
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
例子:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
- 向右 -> 向右 -> 向下 -> 向下
- 向下 -> 向下 -> 向右 -> 向右
解题思路:
如果格子上有障碍,那么我们不考虑包含这个格子的任何路径。我们从左至右、从上至下的遍历整个数组,那么在到达某个顶点之前我们就已经获得了到达前驱节点的方案数,这就变成了一个动态规划问题。我们只需要一个 Grid 数组来存储到达格点的方案数。
算法步骤:
- 状态:既每个格点到达的方案数,存在grid二维数组中,状态初始化:机器人只可以向下和向右移动,因此第一行的格子只能从左边的格子移动到,第一列的格子只能从上方的格子移动到。所以他们根据情况是1或者0.
- 决策:除了初始化的第一行和第一列,余下每个格点都是grid[i][j]=grid[i-1][j]+grid[i][j-1]
- 阶段:由于机器人只可以向下和向右移动,要求的grid[i][j]格,必先知道上边和左边一格的方案数,所有我们从左到右,从上到下计算。
数据分析:
Int grid[N][N]:保存每个格点方案数。
图解过程:
复杂度分析:
时间复杂度:O(N^M)
空间复杂度:O(N^M)
#include <stdio.h>
int uniquePathsWithObstacles(int obstacleGrid[][20], int obstacleGridSize, int obstacleGridColSize){
if (obstacleGridSize == 0 || obstacleGridColSize == 0)
{
return 0;
}
int m = obstacleGridSize;
int n = obstacleGridColSize;
unsigned int dq[m][n]; // 用int的话,测试用例会超范围
int i;
int j;
// 如果起始位置就是1,则直接返回0
if (obstacleGrid[0][0] == 1)
{
return 0;
}
// 将初始位置置为1
dq[0][0] = 1;
// 处理第一列,遇到过障碍物之后,后面的都无法到达,因此都是0
for (i = 1; i < m; i++) {
if (obstacleGrid[i][0] == 1 || dq[i - 1][0] == 0) {
dq[i][0] = 0;
} else {
dq[i][0] = 1;
}
}
// 处理第一行,遇到过障碍物之后,后面的都无法到达,因此都是0
for (j = 1; j < n; j++) {
if (obstacleGrid[0][j] == 1 || dq[0][j - 1] == 0) {
dq[0][j] = 0;
} else {
dq[0][j] = 1;
}
}
for (i = 1; i < m; i++) {
for (j = 1; j < n; j++) {
if (obstacleGrid[i][j]) { // 如果当前的是障碍物,则这个地方无法到达,因此这个位置置为0
dq[i][j] = 0;
} else {
dq[i][j] = dq[i - 1][j] + dq[i][j - 1]; // 到达这个位置可以由上面和左边两条路径到达,是到达上面和左边位置的路径之和
}
}
}
return dq[m - 1][n - 1]; // 返回到达目的地的路径之和
}
int main(){
int a[20][20]={};
int n,m;
printf("输入行数,列数\n");
scanf("%d %d",&m,&n);
printf("输入表格\n");
for(int i=0;i<m;i++) for(int j=0;j<n;j++) scanf("%d",&a[i][j]);
printf("%d",uniquePathsWithObstacles(a, m, n));
}