动态规划 路径类 DP 入门:3 道经典例题(最小路径和 + 迷雾森林 + 过河卒)全解析

动态规划 路径类 DP 入门:3 道经典例题(最小路径和 + 迷雾森林 + 过河卒)全解析

文章目录


路径类 dp 是线性 dp 的⼀种,它是在⼀个 n × m 的矩阵中设置⼀个⾏⾛规则,研究从起点⾛到终点的
⽅案数、最⼩路径和或者最⼤路径和等等的问题。
⼊⻔阶段的《数字三⻆形》其实就是路径类 dp。

矩阵的最小路径和

题目描述

在这里插入图片描述

题目解析
1、状态表示
dp[i][j]表示从[1 1]格子走到[i j]格子时,所有方案下的最小路径和。
2、状态转移方程
我们还是以最后一步来推导状态转移方程,走到最后一个格子dp[n][m]有两种情况,分别是从dp[n - 1][m]到dp[n][m]和从dp[n][m - 1]到dp[n][m],所以dp[n][m]的取值就是取dp[n - 1][m]和dp[n][m - 1]的较小值加a[n][m],所以状态转移方程如下:
dp[i][j] = min(dp[i - 1][j],dp[i][j - 1])+ a[i][j]
3、初始化
因为本题填格子时需要访问左边和上边格子,所以我们需要处理边界情况,在填第一行和第一列格子时会访问到第0行和第0列,但是第0行和第0列是无意义的,所以我们需要把第0行和第0列初始化为无穷大,当填表访问到第0行或第0列格子时由于状态转移方程是取两个格子较小值,所以永远不会取到第0行或第0列格子。
还需要将dp[1][1] 初试化为a[1][1] ,因为[1 1]的最小路径和就是它本身,并且注意在填表时跳过[1 1]格子,首先因为已经将[1 1]格子初始化过了,第二如果把状态转移方程用于[1 1]格子,会把[1 1]格子填为无穷大。

在这里插入图片描述

4、填表顺序
从上往下,从左往右
5、输出结果
dp[n][m]
代码

#include<iostream>#include<cstring>usingnamespace std;constint N =510;int n, m;int a[N][N], dp[N][N];intmain(){//处理输入 cin >> n >> m;for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){ cin >> a[i][j];}}//初始化memset(dp,0x3f3f3f3f,sizeof(dp)); dp[1][1]= a[1][1];//依序填表for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){if(i ==1&& j ==1)continue; dp[i][j]=min(dp[i -1][j], dp[i][j -1])+ a[i][j];}}//输出结果 cout << dp[n][m]<< endl;}

迷雾森林

题目描述

在这里插入图片描述

题目解析
1、状态表示
dp[i][j]表示从[m 1]格子走到[i j]格子时,一共有多少种方案。
2、状态转移方程
还是根据最后一步推导状态转移方程,因为题目规定只能向上或向右走,所以假设最后一个格子为[i j],那么上一个格子可能是[i j - 1]或者[i + 1 j],那么格子[i j]的方案数就是[i j - 1]格子方案数加上[i + 1 j]格子方案数。
但是需要注意,本题只能走空地,如果遇到树是不能走的,也就是只有空地可以用状态转移方程填表,森林格子还是保持默认初始值0。
所以状态转移方程为:
a[i][j] = 0 --> dp[i][j] = dp[i j - 1] + dp[i + 1][j]
a[i][j] = 1 --> dp[i][j] = 0

在这里插入图片描述


3、初始化

  • 因为本题填表时会访问左边格子和下边格子,所以需要将dp数组第0列和第0行格子初始化为0,因为dp数组在全局开辟,所以值默认为0,不需要手动用memset初始化。
  • 因为本题是求解方案数,后续格子方案数就是从第一个格子累加而来,所以将dp[m][1]初始化为1(注意:填表时不填[m][1]格子)
    4、填表顺序
    因为根据前面推导的状态转移方程填表时需要访问左边格子和下边格子,所以填表顺序是从下往上填每一行,填每一行时遵循从左往右。
    5、输出结果
    dp[1][n]

注意:本题规定答案需要对2333取模。
代码

#include<iostream>#include<stdio.h>usingnamespace std;constint N =3010;constint MOD =2333;int m, n;int a[N][N], dp[N][N];intmain(){//处理输入 cin >> m >> n;for(int i =1; i <= m; i++){for(int j =1; j <= n; j++){scanf("%d",&a[i][j]);}}//初始化 dp[m][1]=1;//按序填表for(int i = m; i >=1; i--){for(int j =1; j <= n; j++){//[m][1]格子以及初始化,无需再次填if(i == m && j ==1)continue;if(a[i][j]==0) dp[i][j]=(dp[i][j -1]+ dp[i +1][j])% MOD;}}//输出结果 cout << dp[1][n];return0;}

过河卒

题目描述

在这里插入图片描述

题目解析
由于本题强制规定从[0 0]格子开始填表,所以为了方便处理数组越界问题,我们将题目输入的B 点坐标和马的坐标统一加1,这样就相当于将整个棋盘往下和往右移了一格,就可以从[1 1]格子开始填表
1、状态表示
dp[i][j]表示从[1 1]格子走到[i j]格子时,一共有多少种方案。
2、状态转移方程
还是根据最后一步推导状态转移方程,题目规定卒行走的规则只能向下、或者向右,所以状态转移方程:
dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
但是需要注意只有走到不是马的控制点时才能用状态转移方程填表,如果走到马的控制点不做任何操作,让它保持初始值0即可。
3、初始化
本题需要对a、dp数组分别初始化,dp数组将[1][1]置为1即可,因为方案数问题的答案需要从第一个格子开始累加得到。
a数组的处理思路是将马的9个控制点全部置为1,其余点保持0,在后面根据状态转移方程填表时需要判断a数组对应格子是否为0,如果为0可以填表,不为0则直接continue,不做任何操作。本题对a数组初始化我们借助方向向量实现。
4、填表顺序
从左往右,从上往下
5、输出结果
dp[n][m]

注意:
1、马所在的点也是马的控制点。
2、dp数组要用long long类型,因为方案数类型题目的数据是阶层级别的。

代码

#include<iostream>usingnamespace std;typedeflonglong LL;constint N =25;int n, m, c, d;int a[N][N]; LL dp[N][N];//方向向量int dx[8]={2,2,1,1,-1,-1,-2,-2};int dy[8]={1,-1,2,-2,2,-2,1,-1};intmain(){//处理输入 cin >> n >> m >> c >> d; n++, m++, c++, d++;//初始化 dp[1][1]=1;for(int i =0; i <8; i++){ a[c + dx[i]][d + dy[i]]=1;} a[c][d]=1;//按序填表for(int i =1; i <= n; i++){for(int j =1; j <= m; j++){if(i ==1&& j ==1)continue;if(a[i][j]==0) dp[i][j]= dp[i][j -1]+ dp[i -1][j];}}//输出结果 cout << dp[n][m]<< endl;return0;}

以上就是小编分享的全部内容了,如果觉得不错还请留下免费的赞和收藏
如果有建议欢迎通过评论区或私信留言,感谢您的大力支持。
一键三连好运连连哦~~

在这里插入图片描述

Read more

jdk 国内下载镜像站

以下是一些常用的JDK国内下载镜像: * 华为云镜像: * 地址:https://repo.huaweicloud.com/java/jdk/。 * 特点:提供多种版本的JDK下载,速度快,无需注册登录,镜像内容全面,能满足不同用户对不同JDK版本的需求。 * 清华大学TUNA镜像: * 地址:https://mirrors.tuna.tsinghua.edu.cn/Adoptium/。 * 特点:提供AdoptOpenJDK的镜像下载,对于需要使用OpenJDK相关版本进行开发的用户来说,是一个很好的选择,下载速度相比从国外源下载有较大提升。 * 阿里云开源镜像站: * 地址:https://mirrors.aliyun.com/openjdk/。 * 特点:提供多种开源软件的镜像下载,包括Java JDK,依托阿里云的技术和资源支持,稳定性和下载速度都有保障。 * 网易开源镜像站: * 地址:未明确给出特定JDK镜像地址,但通常在其开源镜像体系中有Java JDK相关镜像,可通过官网查找具体路径。 * 特点:提供多种开源软件

By Ne0inhk
什么是 Java 中的原子性、可见性和有序性?

什么是 Java 中的原子性、可见性和有序性?

👨‍⚕️主页: gis分享者 👨‍⚕️感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️收录于专栏:java 200道热门面试题 文章目录 * 一、🍀回答重点 * 1 ☘️原子性 * 2 ☘️可见性 * 3 ☘️有序性 * 二、🍀扩展知识 * 1. ☘️原子性的保障手段 * 2. ☘️可见性的底层原理 * 3. ☘️有序性与指令重排 * 4. ☘️三大特性的实现方式对比 * 三、🍀面试官追问 一、🍀回答重点 原子性、可见性、有序性是 Java 并发编程的三大核心特性,任何并发 bug 基本都能归到这三类里面。 1 ☘️原子性 原子性指一个操作要么全部执行完,要么压根没执行,中间不会被其他线程打断。比如 i++ 这个操作看着像一行代码,实际上是读取、

By Ne0inhk
从 Spring Boot 3+Java 21 到 Spring Boot 4+Java 25:迁移全指南

从 Spring Boot 3+Java 21 到 Spring Boot 4+Java 25:迁移全指南

随着 Spring Boot 4 正式发布(基于 Spring Framework 6.2)和 Java 25 LTS 的落地,不少团队开始规划升级路线。从 Spring Boot 3+Java 21 迁移到新组合,既要适配框架的新特性,也要利用 Java 25 的性能红利,同时避开兼容性陷阱。本文整理了核心注意要点,帮你平稳过渡~ 一、📋迁移前必做:环境与依赖自查 1. 基础环境适配 * Java 版本门槛:Spring Boot 4 要求最低 Java 25(不再支持 Java 21 及以下),需先升级 JDK

By Ne0inhk

java下载安装教程(附安装包)JDK超详细图文安装教程

文章目录 * 下载JDK安装包 * java安装 * 配置Java环境变量 * IntelliJ IDEA开发工具JDK配置 * 新建项目时配置JDK * 已有项目调整JDK版本 * 通过Maven控制JDK版本 * Java开发环境常见问题解决 * 环境变量配置后java命令仍然无法识别 * 多版本JDK共存技巧 * 深入理解Java版本选择策略 本文提供最新JDK完整安装教程,从下载安装包到环境变量配置的详细流程。包含Java开发工具包的完整部署步骤,附带官方安装包下载链接,适合Java开发初学者和编程学习者快速搭建JDK开发环境。 下载JDK安装包 官网下载渠道 Java Downloads |Oracle 中国 https://www.oracle.com/cn/java/technologies/downloads/#jdk17-windows 国内高速下载链接: 如果官网下载速度慢,可以试试这个国内镜像: https://pan.quark.cn/s/296349c7d9b5 java安装 在当前目录地址栏

By Ne0inhk