动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程最优化的过程。20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的优化问题时,提出了著名的最优化原理,从而创立了动态规划。动态规划的应用极其广泛,包括工程技术、经济、工业生产、军事以及自动化控制等领域,并在背包问题、生产经营问题、资金管理问题、资源分配问题、最短路径问题和复杂系统可靠性问题等中取得了显著的效果。
——百度百科
动态规划与分治法相似,都是通过组合子问题来求解原问题。根据算法导论,Programming 译作“表格法”而不是“编写程序”,“动态规划”这个名字网络上有段子说是用来讨要经费的。
包含如下特征:
OI 中 DP 的含义被极大地扩展了,下面提取两大核心特征
状态 一个含义清晰且独立 (即无后效性) 的子问题 $I $
▶ 使用 \(f_I\) 表示子问题 $ I$ 的答案
▶ 可能需要引入辅助子问题 $g_J, h_K, · · · $
转移 答案 \(f_I\) 通过状态转移方程由其它子问题共同计算得到
▶ 以状态为点,转移为边,构成有向无环图 (DAG)
▶ 边界条件与平凡子问题
▶ 解空间中的任意元素都被恰当考虑
如何理解最后一句话?按照问题类型分类
使用动态规划需要满足以下性质:
1.最优子结构性质。动态规划下一阶段的最优解应该能由前面已经算出的各阶段的最优解导出。
举个简单的例子。下面是一个地图,我们要找一条从左下角(起点)到右上角(终点)、只向右和向上走的路径。

如果要让路径经过的数字总和最大,那么最优路径是下面这条:

可以验证,对于最优路径上的任意一点,最优路径从起点到该点的部分,也正是从起点到该点的所有路径中数字总和最大的那一条。这就叫「满足最优子结构」。
现在换一个「最优」的标准,要求路径经过的数字总和的绝对值最小。那么最优路径是下面这条:

但是,对于最优路径上 -4 这个点,最优路径从起点到该点的部分,却不是从起点到该点的所有路径中,数字总和的绝对值最小的那一条,因为下面这条路径上数字总和的绝对值更小:

这就叫「不满足最优子结构」。
常见的最优化问题,问法一般都是「最大」「最小」,不太会出现「绝对值最小」这种奇葩的最优化标准。而问「最大」「最小」的问题,一般都是满足最优子结构的。 (栗子来自知乎 作者:王赟 Maigo)
2.无后效性。动态规划要求已经求解出的子问题不能受后续阶段的影响,也就是说,动态规划时对于状态空间的遍历应该构成一个有向无环图。
例如CSP-J 2020 方格取数 本题可以向上向下走,如果直接设计 \(f(i, j)\) 的状态表示走到格子 \((i, j)\),那么如下图,状态转移形成环形,会产生后效性。
此时进行动态规划时就要设计一个无后效性的状态,如在原状态 \(f(i, j)\) 的基础上加一维表示方向。
3.子问题重叠。动态规划之所以优于爆搜,就是因为它以空间换时间的形式记录了前面所有状态的最优解。
状态、阶段和决策则是动态规划的三要素。动态规划将相同的计算作用在各阶段的同类子问题,这种计算被称为状态转移方程,其实也就是决策,将当前状态转移到下一状态或更新下一状态,或是根据前面的状态计算当前状态。
一般都是通过数字三角形引入:
Number Triangles
题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
7 3 8 8 1 0 2 7 4 4 4 5 2 6 5在上面的样例中,从 \(7 \to 3 \to 8 \to 7 \to 5\) 的路径产生了最大
输入格式
第一个行一个正整数 \(r\) ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
输出格式
单独的一行,包含那个可能得到的最大的和。
样例 #1
样例输入 #1
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5样例输出 #1
30【数据范围】 对于 \(100\%\) 的数据,\(1\le r \le 1000\),所有输入在 \([0,100]\) 范围内。
方法一:递归
int solve(int i, int j) {
return a[i][j] + (i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1)));
}
如果数据范围很小,可以考虑爆搜,所有路径条数为 \(2^{n - 1}\) ,所以时间复杂度为 \(\Theta(2^n)\) ,无法接受。
方法二:递推
时间复杂度 \(\Theta(n^2)\)
#include<bits/stdc++.h>
using namespace std;
int a[1001][1001];
int main() {
int n = 0;
cin >> n;
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
cin >> f[i][j];
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j <= i; j++)
f[i][j] += max(f[i + 1][j], f[i + 1][j + 1]);
cout << f[0][0];
}
方法三:记忆化搜索
我们画出来方法一的搜索树:

用红色圈起来的地方显然是重复计算了,可以用一个数组来记录搜过的状态,如果再次搜到已搜过的状态,就直接返回记录的值,这样没有了重复搜索,时间复杂度是 \(\Theta(n^2)\).
memset(f, -1, sizeof(f));
int solve(int i, int j) {
if (f[i][j] >= 0) return f[i][j];
return f[i][j] = a[i][j] + (i == n ? 0 :
max(solve(i + 1, j), solve(i + 1, j + 1)));
}
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.
我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO
首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟
我正在尝试动态构建一个多维数组。我想要的基本上是这样的(为简单起见写出来):b=0test=[[]]test[b]这给了我错误:NoMethodError:undefinedmethod`test=[[],[],[]]而且它工作正常,但在我的实际使用中,我不会事先知道需要多少个数组。有一个更好的方法吗?谢谢 最佳答案 不需要像您正在使用的索引变量。只需将每个数组附加到您的test数组:irb>test=[]=>[]irb>test[["a","b","c"]]irb>test[["a","b","c"],["d","e","f"]]
如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail
如何在对象上调用方法名称的嵌套哈希?例如,给定以下哈希:hash={:a=>{:b=>{:c=>:d}}}我想创建一个方法,给定上面的散列,执行以下操作:object.send(:a).send(:b).send(:c).send(:d)我的想法是我需要从一个未知的关联中获取一个特定的属性(这个方法不知道,但程序员知道)。我希望能够指定一个方法链来以嵌套哈希的形式检索该属性。例如:hash={:manufacturer=>{:addresses=>{:first=>:postal_code}}}car.execute_method_hash(hash)=>90210
我有一个ruby程序,我想接受用户创建的方法,并使用该名称创建一个新方法。我试过这个:defmethod_missing(meth,*args,&block)name=meth.to_sclass我收到以下错误:`define_method':interningemptystring(ArgumentError)in'method_missing'有什么想法吗?谢谢。编辑:我以不同的方式让它工作,但我仍然很好奇如何以这种方式做到这一点。这是我的代码:defmethod_missing(meth,*args,&block)Adder.class_evaldodefine_method
假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入
这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经