GESP6级C++考试语法知识(三十九、动态规划的启蒙(四、二维DP))


第四课

《机器人走格子------发现状态转移》


🌟一、故事开始:迷宫机器人

1、在算法王国里,

有一台超级聪明的小机器人。

它叫:

🤖"格子探险家"


2、有一天,

国王给了它一张地图:

复制代码
□ □ □
□ □ □
□ □ □

并告诉它:


3、🏰"你必须从左上角走到右下角!"


但是!

机器人有个奇怪规定:

只能:

  • 向右走 →

  • 向下走 ↓


不能:

  • 向左

  • 向上


4、国王问:


🌟"到底有多少种走法呢?"🌟


5、今天,

我们就来帮助机器人!


🌟二、题目理解

1、我们把地图编号:

复制代码
(1,1) (1,2) (1,3)
(2,1) (2,2) (2,3)
(3,1) (3,2) (3,3)

2、机器人:

(1)从:

复制代码
(1,1)

出发。


(2)目标:

到达:

复制代码
(3,3)

(3)每次:

只能:

  • 向右

  • 向下


(4)问:

🌟一共有多少种走法?


🌟三、先别急着写代码!

1、动态规划最重要的:

🌟不是上来写代码!


2、而是:

🌟"观察规律"!


3、我们先:

自己推一推。


🌟四、先看最简单格子


1、起点

复制代码
(1,1)

2、机器人已经在这里了。

所以:

只有1种方法到达这里。


3、于是:

复制代码
dp[1][1] = 1;

🌟五、再看第一行

1、比如:

复制代码
(1,2)

怎么到?


2、只能:

从左边:

复制代码
(1,1)

走过来!


3、所以:

复制代码
dp[1][2] = 1;

4、同理:

复制代码
(1,3)

也只有:

1种方法。


5、因为:

第一行不能从上面来!


🌟六、再看第一列

1、比如:

复制代码
(2,1)

2、只能:

从上面:

复制代码
(1,1)

下来。


3、所以:

复制代码
dp[2][1] = 1;

4、同理:

第一列所有格子:

也都只有1种方法。


🌟七、真正关键来了!

1、现在:

看中间格子:

复制代码
(2,2)

机器人怎么到这里?


2、最后一步:

只有两种可能:


(1)🌟情况1

从上面:

复制代码
(1,2)

下来。


(2)🌟情况2

从左边:

复制代码
(2,1)

走来。


(3)所以:


到(2,2)的方法数 = 到(1,2)的方法数 + 到(2,1)的方法数


3、于是:

dp22=dp12+dp21


🌟八、发现规律!

1、对于任意格子:

复制代码
(i,j)

2、都只能:

  • 从上面来

  • 从左边来


3、所以:

🌟状态转移公式:

dpij=dpi-1j+dpij-1


🌟九、这就是二维DP!

1、前几课:

我们学的是:

复制代码
dp[i]

2、今天升级了!

变成:

复制代码
dp[i][j]

3、因为:

地图有:


4、所以:

需要二维数组!


🌟十、手动画表格

1、现在:

我们一步一步填表。


2、初始:

1 2 3
1 1 1 1
2 1 ? ?
3 1 ? ?

3、计算 dp22

复制代码
1 + 1 = 2

4、表格变成:

1 2 3
1 1 1 1
2 1 2 ?
3 1 ? ?

5、计算 dp23

来自:

  • 上面 dp13

  • 左边 dp22

复制代码
1 + 2 = 3

表格:

1 2 3
1 1 1 1
2 1 2 3
3 1 ? ?

6、计算 dp32

复制代码
2 + 1 = 3

7、计算 dp33

复制代码
3 + 3 = 6

最终:

1 2 3
1 1 1 1
2 1 2 3
3 1 3 6

8、🌟答案:

复制代码
6

🌟十一、参考代码

复制代码
#include <iostream>
using namespace std;

int dp[105][105];

int main()
{
    int n = 3;
    int m = 3;

    // 第一行
    for(int j = 1; j <= m; j++)
    {
        dp[1][j] = 1;
    }

    // 第一列
    for(int i = 1; i <= n; i++)
    {
        dp[i][1] = 1;
    }

    // 状态转移
    for(int i = 2; i <= n; i++)
    {
        for(int j = 2; j <= m; j++)
        {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }

    cout << dp[n][m];

    return 0;
}

🌟十二、程序运行过程

程序会:


第一步

初始化:

第一行、第一列。


第二步

从左到右,

从上到下,

慢慢填表。


第三步

最后:

复制代码
dp[n][m]

就是答案!


🌟十三、动态规划真正的感觉

很多同学现在会发现:


1、🌟目前学的DP很像:

"填地图"


2、因为:

每个格子的答案,

都来自:

周围格子。


3、这就是:

🌟状态转移!


🌟十四、动态规划四步法(再次强化)

以后同学们使用所有DP:

都尽量按这四步!


🌟第一步:定义状态

这里:

复制代码
dp[i][j]

表示:


"走到(i,j)的方法数"


🌟第二步:初始化

第一行:

全是1。

第一列:

全是1。


🌟第三步:找转移

dpij=dpi-1j+dpij-1


🌟第四步:确定顺序

从:

左上角

慢慢往右下角推。


🌟十五、课堂挑战


🎯挑战1

如果地图是:

复制代码
4 × 4

答案是多少?

请自己画表!


🎯挑战2

修改程序:

输入:

复制代码
n 和 m

输出:

机器人走法数。


🎯挑战3

如果:

地图里有障碍物:

复制代码
X

机器人不能经过。

该怎么办?


提示:

障碍物位置:

复制代码
dp[i][j] = 0;

🌟十六、举一反三

今天我们学的这道题,

是不是很简单?

但是很多DP:

都是从它变来的!


比如:


🎮游戏地图

🧱迷宫问题

🚗最短路径

🪙最少花费

🌳路径统计


🌟十七、本课总结


✅1、二维DP使用:

复制代码
dp[i][j]

✅2、状态表示:

到某个格子的方法数。


✅3、状态转移:

来自:

  • 上面

  • 左边


✅4、动态规划本质:

🌟利用小答案推大答案


✅5、DP最核心:

🌟状态 + 转移


🌟十八、第一阶段总结

恭喜同学们!

我们已经完成:

⚔️动态规划启蒙篇⚔️


现在同学们已经学会:


🌟递归记忆化搜索

🌟DP数组

🌟状态转移

🌟二维DP


通车们已经正式进入:

🚀动态规划的大门!


🌟下阶段预告

接下来,

我们进入:

⚔️第二阶段:线性DP⚔️


第一课:

🐸《青蛙跳台阶大赛》🐸

这次:

青蛙不止能跳2步了!

而且台阶还有坏的,不能跳!

我们再看看:

状态转移还能怎么玩!


相关推荐
QiLinkOS1 小时前
QiLink 技术委员会选举实施细则
c语言·数据结构·c++·单片机·嵌入式硬件·算法·开源
不会C语言的男孩1 小时前
C++ Primer Plus 第13章:类继承
开发语言·c++
承渊政道1 小时前
Linux系统学习【进程控制:进程创建、终止与等待、进程程序替换、自主shell命令行解释器详解】
linux·服务器·c++·学习·ubuntu·bash·远程工作
雪度娃娃1 小时前
转向现代C++——优先选用删除函数而非private未定义函数
java·jvm·c++
QiLinkOS1 小时前
发明人与专利价值共生逻辑
c语言·数据结构·c++·人工智能·单片机·嵌入式硬件·算法
王老师青少年编程1 小时前
信奥赛C++提高组csp-s之平衡树(Treap)
c++·平衡树·treap·信奥赛·csp-s·提高组
磊 子2 小时前
STL之set以及set和map区别
开发语言·c++·算法
Python+992 小时前
C++ 内存模型 & 底层原理
java·jvm·c++
zincsweet2 小时前
Linux 命名管道(FIFO)详解:原理分析、源码封装与通信流程图解
linux·服务器·c++·流程图