欢迎光临
我们一直在努力

GESP6级C++考试语法知识(四十七、动态规划----二维DP(四、网格最大价值DP)


第三阶段第四课

💰《黄金矿工大赛——网格最大价值DP》


🌟一、故事开始:黄金矿工大赛

1、在算法王国里,

一年一度的:

⛏️黄金矿工大赛

开始啦!


2、参赛选手们来到一座巨大的黄金迷宫。

地图长这样:

1 3 2

5 4 1

2 8 6


3、每个格子里,

都藏着黄金!


例如:

5

表示:

这里有5块黄金。


4、比赛规则:


矿工从左上角出发:

🚶


目标:

到达右下角终点。


并且:

🌟一路收集尽可能多的黄金!


5、但是矿工行动不自由。

只能:

→ 向右

向下


不能:


6、国王的问题来了:


🌟怎样走才能拿到最多黄金?


🌟二、先用眼睛观察

1、地图:

1 3 2

5 4 1

2 8 6


2、路线1:

1 → 3 → 2 → 1 → 6

黄金:

13


3、路线2:

1 → 5 → 4 → 8 → 6

黄金:

24


4、明显:

第二条更赚钱!


5、可是如果地图变成:

100 × 100

怎么办?


不可能把所有路线都试一遍!


于是:

⚔️DP登场!


🌟三、和上一课有什么区别?

1、上一课:

🤖机器人迷宫寻宝

求:

有多少种走法?


2、状态转移:

上面 + 左边


3、因为:

统计路线数量。


4、今天:

求的是:

🌟最大价值


5、所以:

思路完全变了!


🌟四、定义状态

1、定义:

dp[i][j]

表示:


2、从起点走到(i,j)

能够获得的最大黄金数


例如:

dp[2][3]

表示:

走到第二行第三列时,

最多能拿多少黄金。


🌟五、来到一个格子

1、例如:

?

位置:

(2,2)


2、矿工从哪里来?


只能:

上面

或者:

左边


3、例如:

4

这个格子价值4。


4、假设:

(1)上面最好路线:

10


(2)左边最好路线:

8


(3)矿工会怎么选?


当然选:

10

那条路!


(4)因为:

黄金更多!


(5)然后再加上当前格子的黄金。


得到:

10 + 4 = 14


🌟六、状态转移公式

1、于是:

当前位置价值 + 上面和左边中的较大值


2、公式来了:

dp[i][j]=a[i][j]+ max(dp[i-1][j],dp[i][j-1])


这就是本课最重要的公式!


🌟七、初始化

1、看起点:

(1,1)


这里只有一种情况:

直接站在这里。


所以:

dp[1][1]=a[1][1];


2、例如:

1


那么:

dp[1][1]=1;


🌟八、先处理第一行

1、地图:

1 3 2

5 4 1

2 8 6


2、机器人只能一直向右。


(1)所以:

dp[1][2] = 1+3 = 4


(2)继续:

dp[1][3] = 4+2 = 6


(3)第一行:

1 4 6


🌟九、处理第一列

1、第一列:

1
5
2


2、只能一直向下。


(1)所以:

dp[2][1]
=
1+5
=
6


(2)继续:

dp[3][1]
=
6+2
=
8


(3)第一列:

1
6
8


🌟十、开始填表

1、原地图:

1 3 2

5 4 1

2 8 6


2、DP表:

(1)先填边界:

1 4 6

6

8


(2)计算:

(2,2)


(3)价值:

4


(4)上面:

4

(5)左边:

6


(6)选大的:

6


(7)得到:

6 + 4 = 10


3、所以:

dp[2][2]=10;


🌟十一、继续填

1、位置:

(2,3)

(1)价值:

1


(2)上面:

6

(3)左边:

10


(4)取最大:

10


(5)得到:

11


2、继续位置:

(3,2)


(1)价值:

8


(2)上面:

10


(3)左边:

8


(4)得到:

18


3、最后位置:

(3,3)


(1)价值:

6


(2)上面:

11


(3)左边:

18


(4)得到:

24


🌟十二、最终DP表

1 4 6

6 10 11

8 18 24


终点:

24


答案:

🌟24


最佳路线:

1 → 5 → 4 → 8 → 6


🌟十三、参考代码

#include <iostream>
using namespace std;

int a[105][105];
int dp[105][105];

int main()
{
int n,m;

cin >> n >> m;

for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin >> a[i][j];
}
}

dp[1][1]=a[1][1];

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

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

// 其余位置
for(int i=2;i<=n;i++)
{
for(int j=2;j<=m;j++)
{
dp[i][j]
=
max(dp[i-1][j],
dp[i][j-1])
+
a[i][j];
}
}

cout<<dp[n][m];

return 0;
}


🌟十四、如何输出最佳路线?

1、很多同学会问:


我知道答案是24。


可是:

🌟到底怎么走的?


2、其实很简单。

(1)从终点开始倒推。


(2)例如:

24

来自:

18

还是:

11


(3)选大的那个。


(4)一路往前找。


(5)最后就能找到:

1

5

4

8

6


3、这叫:

🌟路径还原


以后会专门学习。


🌟十五、课堂挑战


🎯挑战1

计算:

1 2

3 4


最大价值是多少?


🎯挑战2

计算:

5 1 1

2 10 1

1 1 20


最佳路线价值是多少?


🎯挑战3

如果格子里有陷阱:

-5

怎么办?


提示:

公式不用变!


DP仍然成立!


🎯挑战4

如果允许:

三种方向移动。


状态转移如何修改?


提示:

多比较一个方向。


🌟十六、和上一课对比

1、上一课:

求方案数

公式:

dp[i][j]=dp[i-1][j]+dp[i][j-1]


2、这一课:

求最大价值

公式:

dp[i][j]=a[i][j]+ max(dp[i-1][j],dp[i][j-1])


3、这两个题长得特别像!


(1)但一个是:

统计数量


(2)一个是:

求最优解


4、这就是动态规划中最重要的思想之一:

🌟状态定义不同,转移公式就不同!


🌟十七、本课总结


1、✅ 状态定义

dp[i][j]

表示:

到达(i,j)时能获得的最大黄金数。


2、✅ 状态转移

当前位置黄金

上方和左方中的较大值。


3、✅ 初始化

第一行只能向右。

第一列只能向下。


4、✅ 最终答案

dp[n][m]


5、✅ 这是最经典的二维最优路径DP


🌟下节课预告

下一课:

⚔️《超级背包仓库——01背包DP》⚔️


从下一课开始,

我们将进入动态规划最著名、最经典、最重要的一大门派:

🎒背包DP!


赞(0)
未经允许不得转载:171主机测评 » GESP6级C++考试语法知识(四十七、动态规划----二维DP(四、网格最大价值DP)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址