动态规划

动态规划

我怕爱的太早我们不能终老 提交于 2019-11-29 21:50:21
一、动态规划概论: 1、动态规划的基本要素: (1)最优子结构性质:在 一块块的 子问题中,需要最优的解 (2)重叠子问题性质:子问题可能需要重复计算 2、动态规划算法的步骤: · (1) 找出最优解的性质,并刻划其结构特征。 · (2) 递归地定义最优值。 · (3) 以自底向上的方式计算出最优值。 · (4) 根据计算最优值时得到的信息,构造最优解。 3、算法的思想: (1)将整个问题划分成若干个子问题,整个问题的解依赖于子问题的解。 (2)子问题可能需要重复计算,因此可以使用一张表格来记录已经算出来的解 二、矩阵连乘问题 1、问题描述:有n个已经排好序的矩阵,确保是可以连乘的,求一个最优划分的方式来相乘,可以让所需要的相乘次数最少 2、理论基础:(1)两个AmsBsn相乘,所需要的乘法次数是msn (2)一大堆矩阵相乘Ams……Bsn,相乘得到的矩阵的长和宽是Cmn 3、解题的思路: (1)搞清楚最优解的性质和结构关系: 一段长度的矩阵连乘得到的最优解是:将该段矩阵从某处(这一处需要循环的计算来选择出来min的那个)断成两截相乘,其中每一节的相乘次数也是最优的。 (2)写出递归关系: 其中数组p的下标代表的是第i个数组的宽 (3)计算最优值: 列两个表格,一个s,一个m: s:断开位置;m:最优的相乘次数 (4)计算最优解:查表。先查找最终的

【二维动态规划】HDU-1176 免费馅饼

对着背影说爱祢 提交于 2019-11-29 19:41:13
注解 1、本题类似于数塔的思想,从下往上找! 2、dp[i],[j]表示第j秒第i个位置的馅饼数。 3、起始位置是5,所以最后要输出的是dp[0],[5] 代码 #include <iostream> #include <cstring> using namespace std; const int ROW = 100000; const int COL = 11; int dp[ROW][COL]; int main() { int n; scanf("%d", &n); while(n) { memset(dp, 0, sizeof(dp)); for(int i=0; i<n; i++) { int x, T; scanf("%d %d", &x, &T); dp[T][x]++; } for(int i=ROW-2; i>=0; i--) { dp[i][0] += max(dp[i+1][0], dp[i+1][1]); dp[i][10] += max(dp[i+1][9], dp[i+1][10]); for(int j=1; j<10; j++) { int tmpMax = max(dp[i+1][j-1], dp[i+1][j]); tmpMax = max(tmpMax, dp[i+1][j+1]); dp[i][j] += tmpMax; } }

<LeetCode>动态规划——Two Sequences 类型题目

旧时模样 提交于 2019-11-29 19:38:45
一、类型描述 Two Sequences 的题目一般会提供两个sequence,一般问最大/最小、true/false、count(*)这几类的问题。 其中,Two Sequences的动态规划题目的四要素: state:dp[i][j] 一般表示 第一个sequence的前i个字符 和 第二个sequence的前j个字符 怎么怎么样。 Initialization: 这类型动态规划一般初始化dp数组的方式是根据题目的含义初始化第一行和第一列。 function:解决动态规划的function问题,就是找到当前待解决问题dp[i][j] 和 前面解决过的问(例如,dp[i - 1][j]、dp[i][j - 1])的之间的关系。 answer:dp[s1.length()][s2.length()] 二、Leetcode题目举例 97. Interleaving String Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. Example 1: Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac" Output: true Example 2: Input: s1 = "aabcc", s2 = "dbbca", s3 =

动态规划-背包问题

瘦欲@ 提交于 2019-11-29 19:23:04
一、题目描述 有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值,问最多能装入背包的总价值是多大? 样例 样例 1: 输入: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4] 输出: 9 解释: 装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9 样例 2: 输入: m = 10, A = [2, 3, 8], V = [2, 5, 8] 输出: 10 解释: 装入 A[0] 和 A[2] 可以得到最大价值, V[0] + V[2] = 10 挑战 O(nm) 空间复杂度可以通过, 不过你可以尝试 O(m) 空间复杂度吗? 注意事项 A[i], V[i], n, m 均为整数 你不能将物品进行切分 你所挑选的要装入背包的物品的总大小不能超过 m 每个物品只能取一次 二、代码 class Solution { public: /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @param V: Given n items with value V[i] * @return: The maximum value *

Openjudge小练习--动态规划(1)--Maximum sum

拜拜、爱过 提交于 2019-11-29 18:21:04
题目:http://noi.openjudge.cn/ch0206/1481/ 1 #include <cstdio> 2 #include <algorithm>//max()函数 3 using namespace std; 4 int T, n, num[50050], r_max[50050], l_max[50050], ans; 5 int main(){ 6 scanf("%d", &T); 7 while(T--){ 8 scanf("%d", &n); 9 //初始化 10 for(int i=0; i<n; ++i){ 11 scanf("%d", &num[i]); 12 r_max[i] = l_max[i] = -10050; 13 ans = -20100; 14 } 15 //求以第i个数为结束的最大和子串 16 l_max[0] = num[0]; 17 for(int i=1; i<n; ++i) 18 l_max[i] = max(l_max[i-1] + num[i], num[i]); 19 //求以第i个数为开始的最大和子串 20 r_max[n-1] = num[n-1]; 21 for(int i=n-2; i>=0; --i) 22 r_max[i] = max(r_max[i+1] + num[i], num[i]); 23 /

动态规划4 划分型动态规划

喜欢而已 提交于 2019-11-29 17:35:12
题目1:LintCode 108 Palindrome Partitioning II 题目2:LintCode 108 Palindrome Partitioning II Input: "aab" Output: 1 Explanation: Split "aab" once, into "aa" and "b", both palindrome. 将字符串每一段划分成字符串最少划分几次 划分最少,也就是回文串最长 确定状态: 最后一段回文串S[j..N-1] 需要知道S前j个字符串S[0..j-1]最少可以划分成几个字符串 dp[i]:设S前i个字符最少爱可以划分成几个字符串 最后一个回文串长度至少是1,所有j是从0到i-1         假设:最后是一段回文串 dp[i] = min{dp[j]+1} | S[j..i-1]是回文串 区间 [0, 1, 2, j ... i-1 , i]    j=0..i-1 dp[0] = 0;空串可以被分成0个回文串 怎么判断回文串: 奇数 中轴外,左右两边都一样 偶数 左右两边都一样 以每个子串为中心向两边扩展 时间复杂度 0(n^2) 用isPalin[i][j]:表示s[i,j]是否是回文串 dp[i] = min{dp[j]+1} | S[j..i-1]是回文串 ====> dp[i] = min{dp[j]+1} |

典型的动态规划题目总结(斐波那契数列相关)

拥有回忆 提交于 2019-11-29 14:48:31
1.常规跳台阶 一只青蛙一次 可以跳上1级台阶,也可以跳上2级。 求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。 大体思路: 第 i 个楼梯可以从第 i-1 和 i-2 个楼梯再走一步到达,即走到第 i 个楼梯的方法数为走到第 i-1 和第 i-2 个楼梯的方法数之和。所以可以推导出递推公式为: dp[i]=dp[i-1]+dp[i-2] 考虑到 dp[i] 只与 dp[i - 1] 和 dp[i - 2] 有关,因此可以只用两个变量来存储 dp[i - 1] 和 dp[i - 2],使得原来的 O(N) 空间复杂度优化为 O(1) 复杂度。具体非递归代码如下: 2.变态跳台阶 一只青蛙一次 可以跳上1级台阶,也可以跳上2级……它也可以跳上n级 。求该青蛙跳上一个n级的台阶总共有多少种跳法。 大致思路: (1)每一个高度的台阶都可以一步完成,所以每一个位置都有一种基本解 dp[i]=1 (2)除了基本解之外,每一个高度的完成解还受到且仅受到前一个相邻高度dp[i-1]的影响。 (3)因此,每一个高度的最终解都是前一个数的解()+本身的基本解。即, dp[i]=1+dp[i-1]; 3.抢劫一排房子 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是 相邻的房屋装有相互连通的防盗系统

整数划分问题 动态规划

試著忘記壹切 提交于 2019-11-29 14:06:00
ACM,OI等比赛,整数划分为常见的入门题,许久没打比赛,最近做笔试题突然碰到,磕磕绊绊了很久才搞清楚,现在做个笔记。 ------------------------------------------------------------------------------------- 题目可见 hduoj1028 , 简单的讲: 数字N,整数划分的组合数为多少。整数划分表示正整数的和集为N,比如N=4时: 4 = 4; 4 = 3 + 1; 4 = 2 + 2; 4 = 2 + 1 + 1; 4 = 1 + 1 + 1 + 1; 有这5中情况,所以N=4的整数划分的组合数为5。 ------------------------------------------------------------------------------------- 解题,开始DP,先对DP进行状态的设计: 思考的第一步: 考虑到是组合,不能出现重复的情况,比如4=3+1与4=1+3是一种,所以采用“ 划分数中的最大值 ”来限定重复状态。 思考的第二步:状态设计:dp[n][n]表示“ 和为n、最大划分数为m ”时,组合的数量。 思考的第三步:状态转移:由划分数中 是否包含m 分为两种状态,当前组合数等于这两种状态下的组合数之和。 n=1时,无论m等于多少,都只有一种{1}的划分,dp[1][m

关于递归和动态规划的简单理解

。_饼干妹妹 提交于 2019-11-29 13:51:59
1.递归的定义 简单的来说,递归就是一个概念能够用自身来解释,比如说一本字典,每个字词的解释是依靠字典中其他的字词来解释的。一般来说,计算机中遇到的递归问题大多是把一个问题分解成规模更小的子问题求解,再进行合并。 递归的性质 一个具有递归性质的问题,大多具有两个特征,第一个是状态转移方程也就是递归方程,比如在求解阶乘时,n!=n*(n-1)!,就将求解n的阶乘转换为求解n-1的阶乘。第二个特征就是终止条件,一个递归是一类问题的求解,必定有一个结果 无法一只递归下去,有一个结束条件,也就是当问题规模简化的足够小的时候可以直接的出答案。在求解阶乘时,当问题过为1的时候就直接输出1. int f(n) { if(n==1)//终止条件 { return 1; } else { return n*f(n-1);//递归方程 } } 递归的代价 递归执行时,递归函数会被反复地调用,一层一层的进入,到达终止条件后,再一层一层出来,为了保证结果的正确性,每一层函数的运算结果和状态都必须保存在系统所分配的栈里面,当数据量很大的时候,递归所占用的空间和运行时间会非常恐怖,效率也很低 这里再介绍一种和递归类似的但执行效率更高的动态规划算法。 动态规划的性质 递归算法是从顶置低求解问题,而·动态规划算法是从低置顶求解问题,同样也需要状态转移方程方程,和初始条件,相较于递归算法的优势