1.题目描述
shopee的办公室非常大,小虾同学的位置坐落在右上角,而大门却在左下角,可以把所有位置抽象为一个网格(门口的坐标为0,0),小虾同学很聪明,每次只向上,或者向右走,因为这样最容易接近目的地,但是小虾同学不想让自己的boss们看到自己经常在他们面前出没,或者迟到被发现。他决定研究一下如果他不通过boss们的位置,他可以有多少种走法?
输入描述:
第一行 x,y,n (0<x<=30, 0<y<=30, 0<=n<= 20) 表示x,y小虾的座位坐标,n 表示boss的数量( n <= 20)
接下来有n行, 表示boss们的坐标(0<xi<= x, 0<yi<=y,不会和小虾位置重合)
x1, y1
x2, y2
……
xn, yn
输出描述:
输出小虾有多少种走法
2.解题思路
动态规划:
- 初始化,第一行:如果第一行有boss的话,boss位置之后的坐标位置到达不了
dp[0][i] = location[0][i]==1 ? 0:dp[0][i-1];
- 初始化,第一列,如果第一列有boss的话,boss之后的坐标位置到达不了
dp[i][0] = location[i][0]==1?1:dp[i-1][0];
- 状态转移方程:
如果遇到boss,则之前的作废,此时dp[i][j] = 0;否则为现在位置的走法总数=现在位置的左边总数+现在位置的下边总数
dp[i][j] = location[i][j] == 1 ? 0:dp[i-1][j]+dp[i][j-1];
3.代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sr = new Scanner(System.in);
int x = sr.nextInt();
int y = sr.nextInt();
int n = sr.nextInt();
int [][] location = new int[x+1][y+1];
for(int i = 0;i<n;i++){
int x1 = sr.nextInt();
int y1 = sr.nextInt();
if(x1<=x && y1<=y)
location[x1][y1] = 1;
}
System.out.println(solution(location,x,y));
}
private static long solution(int[][] location, int x, int y) {
long dp[][] = new long[x+1][y+1];
//行初始化
dp[0][0] = 1;
for(int i = 1;i<=y;i++){
dp[0][i] = location[0][i]==1 ? 0:dp[0][i-1];
}
//列初始化
for(int i = 1;i<=x;i++){
dp[i][0] = location[i][0]==1?1:dp[i-1][0];
}
//动态规划
for(int i = 1;i<=x;i++){
for(int j = 1;j<=y;j++){
dp[i][j] = location[i][j] == 1 ? 0:dp[i-1][j]+dp[i][j-1];
}
}
return dp[x][y];
}
}
题型为leetcode-63:不同路径2的应用,
先引入leetcod-62-不同的路径:https://leetcode-cn.com/problems/unique-paths/
1 题目描述
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。问总共有多少条不同的路径?
2.解题思路
(1)初始化
- 1) 从[0,0]走到[0,0]的路径,即没走,设
dp[0][0] = 0
;- 2) 如果mn的n为1,即机器人在m1走,只能有一条路径,即
dp[i][0] = 1
;- 3) 如果mn的m为1,即机器人在1n走,只能有一条路径,即
dp[0][i] = 1
;(2) 动态规划核心算法
机器人每次只能向下或者向右移动一步。即机器人dp[i][j]的路径由dp[i-1][j]和dp[i][j-1]决定,即
dp[i][j] = dp[i-1][j]+dp[i][j-1]
3.代码
class Solution {
public static int uniquePaths(int m, int n) {
if(m < 0 || n < 0)
return 0;
int dp[][] = new int[m][n];
//初始化
dp[0][0] = 0;
//初始化列
for(int i = 0;i<n;i++){
dp[0][i] = 1;
}
//初始化行
for(int i = 0;i<m;i++){
dp[i][0] = 1;
}
//动态规划
for(int i =1;i<m;i++){
for(int j = 1;j<n;j++){
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
}
leetcode-63:不同路径2:https://leetcode-cn.com/problems/unique-paths-ii/
1.题目描述
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出:
2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
向右 -> 向右 -> 向下 -> 向下
向下 -> 向下 -> 向右 -> 向右
2.解题思路
如果第一个格点 obstacleGrid[0][0] 是 1,说明有障碍物,那么机器人不能做任何移动,我们返回结果 0。如果 obstacleGrid[0][0] 是 0,我们初始化这个值为 0 然后继续算法。
- (1)动态规划初始化
- 1)obstacleGrid[0][0] == 0,表示没障碍,路径只有一条;
dp[0][0] = 1
;- 2)遍历第一行,如果有一个格点初始值为 1 ,说明当前节点有障碍物,没有路径可以通过,设值为 0 ;否则设这个值是前一个节点的值
dp[0][j] = dp[0][j-1]
。- 3)遍历第一列,如果有一个格点初始值为 1 ,说明当前节点有障碍物,没有路径可以通过,设值为 0 ;否则设这个值是前一个节点的值
dp[i][0] = obstacleGrid[i-1][0]
。- (2) 动态规划核心算法
从 obstacleGrid[1][1] 开始遍历整个数组,如果某个格点初始不包含任何障碍物,就把值赋为上方和左侧两个格点方案数之和
dp[i][j] = dp[i-1][j] + dp[i][j-1]
。
如果这个点有障碍物,设值为 0 ,dp[i][j] = 0
;这可以保证不会对后面的路径产生贡献。
3.代码
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int row = obstacleGrid.length;
int col = obstacleGrid[0].length;
if(obstacleGrid[0][0] == 1 || obstacleGrid==null){
return 0;
}
int dp[][] = new int[row][col];
dp[0][0] = 1;
//行初始化
for(int i = 1;i<col;i++){
dp[0][i] = obstacleGrid[0][i]==1 ? 0 : dp[0][i-1];
}
//列初始化
for(int i = 1;i<row; i++){
dp[i][0] = obstacleGrid[i][0] == 1? 0:dp[i-1][0];
}
//动态规划
for(int i = 1;i<row;i++){
for(int j = 1;j<col;j++){
dp[i][j] = obstacleGrid[i][j] == 1 ? 0 : dp[i-1][j]+dp[i][j-1];
}
}
return dp[row-1][col-1];
}
}