关于动态规划的一点小想法
本文最后更新于 2024年6月7日 下午
最近一直在做动态规划的题,也算有了一些自己的小感悟,暂时总结一下
首先看一道例题
描述
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。
输入
输入一行 3 个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
输出
要求输出一个整数,表示正好取 k 个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
1 |
|
1 |
|
思考
- 动态规划,我们知道这是一种记录 T 时刻状态,通过状态转移方程,推导出 T+1 时刻的状态的算法,是一种空间换时间的算法,状态的记录通常使用数组。
- 求解目标:解决动态规划的问题,首先我们需要明确求解的目标是什么?求解目标就是数组元素的值。上面这道例题中,求解的目标就是到达终点满足条件的方法数目。那么数组元素中记录的值就是方法数。
- 数组:其次我们需要解决的是数组的维数,这个问题我们可以通过观察变量的数目来确定。上面的例题中,影响结果的变量有:横 m、纵坐标 n、物品最大价值 mp、物品数目 k 四个,所以需要引入的是一个数组四维数组。
- 起点:既然是根据前项推出后项,那么如同递归需要有一个出口一样,动态规划需要至少有一个起点——也即数组的某些元素的值是可以在初始阶段确定的。
- 在上面的例题中,
(1,1,0,0)
元素的值可以确定(到达终点(1,1)
位置,一个元素都不拿,物品的最大价值为 0,明显只有一种方法) - 同时
(1,1,1,goods[1][1])
元素的值也是能确定(只拿一个物品,那么只能拿(1,1)
这个位置的物品,拿了之后物品最大价值的就是(1,1)
的价值)
- 在上面的例题中,
- 状态转移方程:最后需要明确的就是状态转移方程,在上面的例题中,到达一个位置拿 k 个物品,有两种方式。
-
不拿当前的物品,那么
Num[i][j][k][mp]+=Num[i-1][j][k][mp]+Num[i][j-1][k][mp]
-
当前位置的物品价值大于已经拿到的最大价值的情况下,那么可以拿起当前物品。但请注意拿起后物品数加一,已经拿到的最大价值也改变。
Num[i][j][k+1][goods[i][j]]+=Num[i-1][j][k][mp]+Num[i][j-1][k][mp]
-
到这里这道题的总体思路也就解决了,除此外到达终点的物品最大价值可能有多种情况,只要将所有价值情况下的方法数求和即可。
代码
1 |
|