动态规划的分类解析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
} int ans = 0; for (int i = 1; i <= n; i++)
ans = max(ans, f[i]); printf(“%d\n“, ans);
最低通行费
一个商人穿过一个 N*N 的正方形的网格,去参与一个 特别重要的商务活动。他要从网格的左上角进,右下 角出。每穿越中间1个小方格,都要花费1个单位时间。 商人必需在(2N-1)个单位时间穿越出去。而在经过中 间的每个小方格时,都需要缴纳肯定的费用。
opt[i]=opt[k]+bri[i];
以上都是线性动规的一些例 题,它们的根底时间简单度 都是O(N2)
装箱问题
有一个箱子容量为maxv(正整数, maxv≤20230),同时有n件物品(0≤n≤30), 每件物品有一个体积vi(正整数) 。要求从 这n件物品中任取假设干件装入箱内,使 箱子的剩余空间最小。
这是线性动态规划的经典例题。
代码
for (int i = 1; i <= n; i++) scanf(“%d“, &a[i]);
for (int i = 1; i <= n; i++) { int mx = 1; for (int j = 1; j < i; j++) if (a[j] >= a[i]) mx = max(mx, f[j] + 1); f[i] = mx;
假设s1‥si(2≤i≤n)中插入j个乘号,其中s1‥sk 中插入了j-1个乘号,即乘式中的第j+1项为 sk+1‥si(j≤k≤i-1):
分析
设 ans[i][j]——长度为i的数串中插入j个乘
号的最大乘积〔整型数组〕。明显 ans[i][0]=s1..si对应的整型数组; ans[i][j]=max{ans[k][j-1]×sk+1..si}
printf(“%d\n”, f[n][n]);
乘积最大
国际数学联盟确定的“2023—世界数学年”,又恰逢我国著 名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏 金坛,组织了一场别开生面的数学智力竞赛活动,你的好朋 友XZ也有幸得以参与。活动中,主持人给全部参与活动的选 手出了这样一道题目:
题目给出独木桥的长度L,青蛙跳动的距离范围S,T, 桥上石子的位置。你的任务是确定青蛙要想过河, 最少需要踩到的石子数。
分析
从正面来考虑的话,这个问题是一个搜 寻性的问题,需要考虑从当前点动身可 以跳到的全部点。
然而从反面考虑的话,我们只需要考虑 那些能到用一步到达当前点的全部点中, 踩到石头数最小的那个。
动态规划的条件
而在求解的过程中一道能使用动规解决的题必需具备 以下几个条件 无后效性,即某阶段的状态一旦确定,则此后过程的演化不再 受此前各状态及决策的影响。也就是说,“将来与过去无 关”,当前的状态是此前历史的一个完整总结,此前的历史 只能通过当前的状态去影响过程将来的演化。
满足最优子构造性质,即一个问题的最优解必需是在子问题 取得最优解的状况下决策出来的
状态确实定
我们用opt[i][j]〔布尔〕表示前i个物品是 否能到达j体积。则opt[i][j]的值取决于前i1个物品能否到达j体积,或者是前i-1个物 品能否到达j-v[i]体积
则有opt[i][j]=(opt[i-1][j-v[i]])or(opt[i-1][j]) 初值为opt[0][0]=true;其他都为false
假设能够保存已解决的子问题的答案,而在需 要时再找出已求得的答案,就可以避开大量重 复计算,从而得到多项式时间算法。
由此不难得出结论:动态 规划实质就是
记忆化搜寻
下面这个数塔的例子将形象地向我们展现这 样的结论
给你一个数字三角形, 形式如下:
1
23
8 5 18
14 2 1 10
一条
找出从第一层到最终一层的
动态规划
动态规划
什么是动态规划 动态规划的条件 动态规划的关键 几种常见动态规划的种类 例题分析
什么是动态规划
动态规划算法与分治法类似,其根本思想也是 将待求解问题分解成假设干个子问题
但是经分解得到的子问题往往不是相互独立的。 不同子问题的数目常常只有多项式量级。在用 分治法求解时,有些子问题被重复计算了很屡 次。
{计算状态转移方程} end;{for} 输出最大乘积ans[n][m];
过河
在河上有一座独木桥,一只青蛙想沿着独木桥从河 的一侧跳到另一侧。在桥上有一些石子,青蛙很厌 烦踩在这些石子上。由于桥的长度和青蛙一次跳过 的距离都是正整数,我们可以把独木桥上青蛙可能 到达的点看成数轴上的一串整点:0,1,……,L 〔其中L是桥的长度〕。坐标为0的点表示桥的起点, 坐标为L的点表示桥的终点。青蛙从桥的起点开头, 不停的向终点方向跳动。一次跳动的距离是S到T之 间的任意正整数〔包括S,T〕。当青蛙跳到或跳过 坐标为L的点时,就算青蛙已经跳出了独木桥。
分析
这是一个最根底的背包问题,只需要考虑 选取哪几个物品放入箱子,可以使得剩余 体积最小。
这道题的根本做法固然还是穷举放进背包 的物品编号。假设我们把取该物品记为1, 不取该物品记为0,那么使用某种放入方式 将对应一个2进制串,因此这类问题也被称 为0-1背包问题.
假设我们不从物品角度考虑,而是从体积 角度考虑的话,就会觉察,这个问题还可 以被描述为,w[i]的体积是否能由这些物品 得到。
〔1≤i≤n, 1≤j≤min{i-1,m},j≤k≤i-1〕 ans[n][m]即为其解。
分析
由于乘式中第j+1项sk+1‥si为常量,因此 要使得ans[i][j]最大,则s1‥sk中插入j-1 个乘号的乘积必需最大;同样,为了查 找第j个乘号的最正确插入位置,必需一 一查阅子问题ans[j][j-1]‥ans[i-1][j-1]的解。 明显该问题具备无后效性、最优子构造 的特征,适用于动态规划方法。
设有一个长度为N(N≤40)的数字串,要求选手使用M(M≤6)个 乘号将它分成M+1个局部,找出一种分法,使得这M+1个局 部的乘积最大。
同时,为了帮助选手能够理解题意,主持人还举了如下一个 例子:
有一个数字串:312,当N=3,M=1时会有两种分法: ⑴3×12=36 ⑵31×2=62 这时,符合题目要求的结果是:31×2=62。现在,请你帮助
线性动规 区间动规
背包问题 树形动规
拦截〔Noip2023〕
某国为了防范敌国的攻击,进展出一种拦截 系统。但是这种拦截系统有一个缺陷:虽然 它的第一发炮弹能够到达任意的高度,但是 以后每一发炮弹都不能高于前一发的高度。 某天,雷达捕获到敌国的来袭。由于该系统 还在试用阶段,所以只有一套系统,因此有 可能不能拦截全部的。输入依次飞来的高度, 计算这套系统最多能拦截多少。
状态确实定
状态的表示——f[i],表示当第i个必需拦截时, 前i个中最多能拦截多少。
每个有肯定的高度,当前状态就是以第i个为 最终一个拦截的。以前状态就是在这个之前 拦截的那个。
对于f[i],我们考察在i之前位置的,找到全部 可以连接上的k〔即满足其高度大于等于第i 个〕,选择其中f[k]值最大的一个,f[i]=f[k]+1; 假设没有满足条件的k,则f[i]=1。
即opt[i]=min{opt[k] (max{0,i-t}≤k≤is)}+bri[i];
代码
For i←1 to n do opt[i]=10000000;
opt[0]=0;
For i←s to L+t do
for k←max{0,i-t} to i-s do
if (opt[k]+bri[i]<opt[i])
状态确实定
我们用ans[i][j]表示前i个字符插入j个乘号可以获 得的最大值
则有: ans[i][0]=s1..si ans[i][j] = max{ans[k][j-1]×sk+1..si} (j≤k≤i-1) ans[n][m]即为其解。
代码
输入n,m和数串s; for i←1 to n do ans[i][0]←s1..si对应的整数数组; for i←2 to n do {阶段:枚举数串的长度}
}
else opt[i][j] = opt[i - 1][j];
采药
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最宏大 的医师。为此,他想拜四周最有威望的医师为师。医师为 了推断他的资质,给他出了一个难题。医师把他带到一个 处处都是草药的山洞里对他说:“孩子,这个山洞里有一 些不同的草药,采每一株都需要一些时间,每一株也有它 自身价值。我会给你一段时间,在这段时间里,你可以 采到一些草药。假设你是一个聪明的孩子,你应当可以让 采到的草药的总价值最大。”
这个商人期望在规定时间内用最少费用穿越出去。请 问至少需要多少费用?
留意:不能对角穿越各个小方格〔即,只能向上下左 右四个方向移动且不能离开网格〕。
最低通行费
输入 第一行是一个整数,表示正方形的宽度
N (1 <= N < 100); 后面 N 行,每行 N 个不大于 100 的整
数,为网格上每个小方格的费用。 输出 至少需要的费用。
最终输出opt[n][n];
代码
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) scanf(“%d”, &a[i][j]);
for (int i = 1; i <= n; i++) for (int j = 1; j <=n; j++) f[i][j] = min(f[i-1][j], f[i][j-1]) + a[i][j];
代码
memset(opt, 0, sizeof(opt));
opt[0][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= maxv; j++)
if (j >= v[i]) {
opt[i][j] = opt[i - 1][j] | opt[i - 1][j - v[i]];
for j←1 to min{i-1,m} do {状态:枚举长度为i的数串中插入的乘号个数}
for k←j to i-1 do {决策:枚举第j个乘号的插入位置}
begin next←sk+1..si对应的整数数组; {计算第j+1项} ans[i][j]←max{ans[i][j], ans[k][j-1]×next};
分析
这个问题的关键在于觉察对移动方向的 限制:即由于必需在(2N-1)单位时间内完 成移动,因此仅能向下或者向右移动。
当移动方向限定后,不难看出这个问题 就是变形的数塔问题,于是可以借助动 态规划高效解决。
状态确实定
我们用opt[i][j]表示从左上角入口移动到 第i行j列的最小代价。
则opt[i,j]=min{opt[i-1][j], opt[i][j-1]) + a[i][j];
你的好朋友XZ设计一个程序,求得正确的答案。
分析
由于自然数位数的上限为40,乘号数的上 限为6,因此最大乘积位数的上限接近42 位。明显,运算任何整数类型都无法容纳 如此之大的数据,只能承受高精度运算, 限于篇幅,对于高精度的加法运算、乘法 运算和比较大小的运算,这里不作介绍, 只是对的乘号最正确插入方式进展探讨:
小或
路,使得所经过的权值之和最
者最大.
固然,大家都很清晰的知道转移方程为 opt[i][j]=max{opt[i-1][ j], opt[i-1][j1] }+a[i][j],边界条件特殊处理即可。
但只要认真想想就会觉察,这不过是一 个加了强力剪枝的记忆化搜寻而已,由 于每个点我们只记录到当前节点的最优 解,因此省去了大量的重复计数和明显 不是最优解的状况,从而使运行速度有 了极大的优化
动态规划的过程可以简洁地描述为
找出最优解的性质,并刻画其构造特征。 递归地定义最优值。 以自底向上的方式计算出最优值。 依据计算最优值时得到的信息,构造最
优解。
动态规划的关键
下 了面 解让
这我
些们
有明确的状态
根通 本过
状态转移方程清晰正确
动几 规个
的例
几种常见动规的种类
思子 考来


相关文档
最新文档