动态规划

动态规划——数字三角形(递归or递推or记忆化搜索)

空扰寡人 提交于 2020-03-03 22:18:58
动态规划的核心就是状态和状态转移方程。 对于该题,需要用抽象的方法思考,把当前的位置(i,j)看成一个状态,然后定义状态的指标函数d(i,j)为从格子出发时能得到的最大和(包括格子本身的值)。 在这个状态定义下,原问题的解就是d(i,j). 下面看一下不同状态之间如何转移。从格子(i,j)出发有两种策略。如果向左走,则到(i+1,j)后需要求“从(i+1,j)出发能得到的最大和”这一问题,即d(i+1,j)。 类似的,往右走之后需要求解d(i+1,j+1).由于可以在这两个决策中自由选择,所以应选择其中较大者。换句话说就是得到状态转移方程 d(i,j)=a(i,j)+Max(d(i+1,j),d(i+1,j+1)) 这样就保证了子树的最优,这个性质称为最优子结构。 用直接递归的方法计算状态转移方程,效率往往十分低下。其原因是相同的子问题被重复计算了多次。 因此我们对其优化采用了递推算法或者采用记忆搜索的方式。 递推计算就是把每个问题直接罗列出来,因此不会重复。 记忆搜索的程序依然是递归的,但是把计算结果放在了数组d中。开始将所有状态置为-1,只要是计算过的状态就就变成非负,因此只要判断是否d[i][j]>=0,就知道它是否计算过。 #include<iostream> #include<string> using namespace std; void input(int a[]

矩阵连乘问题

元气小坏坏 提交于 2020-03-03 22:08:39
由于矩阵的乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这中计算次序 可以用加括号的方式来确定。例如,矩阵连乘积A1A2A3A4可以有5种不同的完全加括号方式: (A1(A2(A3A4))) (A1((A2A3)A4)) ((A1A2)(A3A4)) ((A1(A2A3))A4) (((A1A2)A3)A4) 矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。若A是一个p*q的矩阵, B是一个q*r的 矩阵,其乘机C=AB是一个p*r的矩阵,总共需要pqr次数乘。 为了说明在计算矩阵连乘积 时,加括号方式对整个计算量的影响,我们考察计算3个矩阵A1A2A3的连乘积的例子。 这3个矩阵的尺寸分别为10*100,100*5和5*50。 若以((A1A2)A3)这种方式计算, 3个矩阵的连乘积需要的数乘次数为7500。 若以(A1(A2A3))这种方式计算, 所需的数乘次数为75000。显然,在即算矩阵连乘积时,加括号方式对计算量有很大影响。 1.分析最优解的结构 设计求解具体问题的动态规划算法的第一步是刻画该问题的最优解的结构特征。我们将矩 阵连乘积AiAi+1....Aj简记为A[ i : j ]。考察计算A[ 1: n]的最优计算次序。设这个计算 次序在矩阵Ak和Ak+1之间将矩阵链断开,1<=k<n,则其相应的完全加括号形式为((A1...Ak) (Ak+1..

五大常用算法之二:动态规划算法,会用的程序员工资都翻倍了

醉酒当歌 提交于 2020-03-03 18:50:57
一、基本概念 动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。 二、基本思想与策略 基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。 由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。 与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。 三、适用的情况 能采用动态规划求解的问题的一般要具有3个性质: (1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。 (2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。 (3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。

动态规划

喜你入骨 提交于 2020-03-03 15:43:07
目录 1. 步骤 2. 要素 3. 装配线调度 4. 矩阵链乘 5. 最长公共子序列(Longest Common Subsequece) 6. 最优二叉查找树(Optimal Binary Search Tree) 1. 步骤 描述问题的最优解(optimal solution)结构特征 递归定义最优解值 自底向上 计算最优解值 从已计算得到的最优解值信息中构造最优解 2. 要素 最优子结构和重叠子问题 最优子结构性质是指一个问题的最优解中所包含的所有子问题的解都是最优的。 动态规划避开了递归时,重复计算相同子问题的过程,对每个子问题只解一次,而后将其保存在一个 表格中,当再次需要的时候,查表获取。 3. 装配线调度 最优子结构性质:如果问题的解是最优的,则所有子问题的解也是最优的。在这里,描述为最优 路径的子路径也是最优的。 最优子结构证明:剪枝法 ∵如果子路径P1从开始到S1,j-1不是最优的,那么一定存在一条从开始到S1,j-1的更优子路径P2, 当用P2去替换原子路径P1后,将得到一条比原路径更优的路线,这与假设从开始到S1,j是一条最 优路线矛盾。 ∴子路径P1一定也是最优的 递归定义最优路线的最快时间 最快时间 f =min(f1[n]+x1,f2[n]+x2) 要得到f 值,需要计算fi[j]的每个值 f1[j]=min{f1[j-1]+a(1,j),f2[j-1]

算法进阶路径

别来无恙 提交于 2020-03-03 10:34:39
第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码, 因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打 出来. 1.最短路(Floyd、Dijstra,BellmanFord) 2.最小生成树(先写个prim,kruscal要用并查集,不好写) 3.大数(高精度)加减乘除 4.二分查找. (代码可在五行以内) 5.叉乘、判线段相交、然后写个凸包. 6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简) 7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式. 8. 调用系统的qsort, 技巧很多,慢慢掌握. 9. 任意进制间的转换 第二阶段:练习复杂一点,但也较常用的算法。 如: 1. 二分图匹配(匈牙利),最小路径覆盖 2. 网络流,最小费用流。 3. 线段树. 4. 并查集。 5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp 6.博弈类算法。博弈树,二进制法等。 7.最大团,最大独立集。 8.判断点在多边形内。 9. 差分约束系统. 10. 双向广度搜索、A*算法,最小耗散优先. 相关的知识 图论 路径问题 0/1边权最短路径 BFS 非负边权最短路径(Dijkstra) 可以用Dijkstra解决问题的特征 负边权最短路径 Bellman-Ford Bellman

【C++】树型动态规划

Deadly 提交于 2020-03-03 10:28:28
树型动态规划 摘要 例1 没有上司的舞会 题目描述 输入描述 输出描述 样例输入 样例输出 思路 1 定义状态: 2 转移方程: 3 初始值: 4 答案: 代码 例2 数字转换 题目描述 输入描述 输出描述 样例输入 样例输出 样例说明 数据范围 代码 例3 二叉苹果树 题目描述 输入描述 输出描述 样例输入 样例输出 数据范围 思路 1 状态定义 2 转移 3 初始 4 答案 代码 例4 选课 题目描述 输入描述 输出描述 样例输入 样例输出 数据范围 思路 1 状态: 2 转移: 3 初始值: 4 答案: 代码 摘要 之所以这样命名树规,是因为树规的这仙特殊性:没有环,dfs是不会重复,而且具有明显而又严格的层数关系。利用这仙特性,我们可以很清晰地根据题目写出一个在树(型结构)上的记忆化搜索的程序。而深搜的特点,就是“不撞南墙不回头”。这仙点在之后的文章中会详细的介绍。 关键字:树,动态规划,递归 例1 没有上司的舞会 Luogu-1352 链接: https://www.luogu.com.cn/problem/P1352 我记得原题是“Ural大学” 还是给出原题吧。 题目描述 Ural大学有N个职员,编号为1到N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大

动态规划之区间动态规划

只愿长相守 提交于 2020-03-03 05:57:13
区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来由很大的关系。令状态 f [ i , j ] f[i,j] f [ i , j ] 表示将下标位置 i i i 到 j j j 的所有元素合并能获得的价值的最大值,那么 f [ i , j ] = max ⁡ { f [ i , k ] + f [ k + 1 , j ] + c o s t } f[i,j]=\max\{f[i,k]+f[k+1,j]+cost\} f [ i , j ] = max { f [ i , k ] + f [ k + 1 , j ] + c o s t } ,其中 c o s t cost c o s t 为将这两组元素合并起来的代价 1 , i ≤ k < j i\leq k<j i ≤ k < j 。 例题一 石子合并 例题: luogu1880 [NOI1995]石子合并 思路参考自: https://oi-wiki.org/dp/interval/ 。简单来说,三重for循环,第一重是长度 l e n len l e n ,第二重是开始下标 i i i (前两重可以确定结束下标 j j j ),第三重是合并位置 k k k 。 解决环的问题:复制一份,变成 2 n 2n 2 n 的序列。 注意点 :最小值初始化 f 1 [ i ]

C++.编程题.假期.动态规划

断了今生、忘了曾经 提交于 2020-03-03 05:54:35
由于业绩优秀,公司给小Q放了 n 天的假,身为工作狂的小Q打算在在假期中工作、锻炼或者休息。他有个奇怪的习惯:不会连续两天工作或锻炼。只有当公司营业时,小Q才能去工作,只有当健身房营业时,小Q才能去健身,小Q一天只能干一件事。给出假期中公司,健身房的营业情况,求小Q最少需要休息几天。 4 1 1 0 0 0 1 1 0 2 用到动态规划,将大问题变成小问题递推解决,因为第二天只能做昨天没做过的事,每一天的某件事的递推数字都得是昨天其它两件事的最大值+1去递推,最终得到的最后三件事的最大值则是不休息做事的天数的最大值,用总天数减去做事日则是休息日 #include <iostream> #include <vector> #include <algorithm> using spacename std int main(){ int n; cin >> n; vector<int> work(n), slg(n); for(int i=0; i<n; ++i) cin >> work[i]; for(int i=0; i<n; ++i) cin >> slg[i]; vector<vetor<int>> dp(3, vector<int>(n+1)); int dp[0][0] = dp[1][0]=dp[2][0]=0; for(int i=1; i<=n; ++i){ dp[0]

LeetCode 32,并不Hard的难题,解法超级经典,带你领略动态规划的精彩

老子叫甜甜 提交于 2020-03-02 08:52:11
本文始发于个人公众号: TechFlow ,原创不易,求个关注 今天给大家分享的是LeetCode当中的32题,这是一道Hard难度的题。也是一道经典的字符串处理问题,在接下来的文章当中,我们会详细地解读有关它的三个解法。 希望大家不要被题目上的标记吓到,虽然这题标着难度是Hard,但其实真的不难。我自信你们看完文章之后也一定会这么觉得。 链接 Longest Valid Parentheses 难度 Hard 描述 给定一个只包含左右括号的字符串,返回最长能够组成合法括号的长度 Given a string containing just the characters '(' and ')' , find the length of the longest valid (well-formed) parentheses substring. 样例 1: Input: "(()" Output: 2 ## Explanation: The longest valid parentheses substring is "()" 样例 2: Input: ")()())" Output: 4 ## Explanation: The longest valid parentheses substring is "()()" 思考 我们来分析一下题目,这题的题目很容易理解

网易——合唱团,动态规划,限制了个数和位置差

倾然丶 夕夏残阳落幕 提交于 2020-03-02 08:06:35
题目描述 有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗? 输入描述: 每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。 输出描述: 输出一行表示最大的乘积。 示例1 输入 3 7 4 7 2 50 输出 49 【解决】 ① 动态规划!!!! 因为学生能力的输入可能为正也可能为负,因此要使用两个标记数组分别记录最大乘积和最小乘积。 【定义】 max[k][n]表示在最终位置为n时有k个学生的最大乘积; min[k][n]表示在最终位置为n时有k个学生的最小乘积; 【初始化】 max[1][i]=ability[i];位置i上有1个学生的最大乘积为该学生的能力值; min[1][i]=ability[i];位置i上有1个学生的最小乘积为该学生的能力值; 【递推】 max[j][i]=Math.max(max[j][i],Math.max(max[j - 1][pre] *