动态规划

动态规划之最少硬币问题

 ̄綄美尐妖づ 提交于 2020-02-16 06:27:44
/******************************************************************** ** @file test.cpp ** @author liuke ** @date Fri Apr 22 23:50:50 2011 ** @brief **************************动态规划实现******************************** 长度为m的数组f[1...m]中存放一系列子结果,即f[i]为要凑的钱数为i时 所需的最少硬币数,则c[m]为所求; 当要找的钱数i(1<i<m)与当前所试探的硬币面值k相等时,结果为1,即c[i]=1 当i大于当前所试探硬币面值k时,若f[i]为0,即还未赋过值,且c[i-k]不为0, 即从i元钱中刨去k元后剩下的钱数可以找开, 则c[i]=c[i-k]+1 若f[i]不为0,即已赋过值,则f[i]为f[i-k]+1和f[i]中较小的 ** **@version Copyright (c) 2010,河南理工大学-信管08-三班 *******************************************************************/ #include<iostream> #include<cstring> using

动态规划常见问题汇总——持续更新

别说谁变了你拦得住时间么 提交于 2020-02-15 23:50:52
动态规划的特点:  需要在给定约束条件下优化某种指标时,动态规划很有用。  问题可分解为离散子问题时,可使用动态规划来解决。  每种动态规划解决方案都涉及 网格 。  单元格中的值通常就是你要优化的值。  每个单元格都是一个子问题,因此你需要考虑如何将问题分解为子问题。  没有放之四海皆准的计算动态规划解决方案的公式。 因此,划分子问题的方式不同,得到的网格就不同,递推公式自然也就不同。 本博客记录一些常见的动态规划问题,方便查询。 目录 最长公共子串 描述 划分1 划分2 例题1 例题2 01背包问题 例题1: 例题2: 最大递增子序列 描述 思路 例题1 其他可以用动态规划解决的问题 例题1 最长公共子串 描述 有两个字符串(可能包含空格),请找出其中最长的公共连续子串,输出其 长度 。(长度在1000以内) 例如: 输入:acbcbcef 和abcbced 输出:5 划分1 递推公式为: //二维数组遍历循环 if(A[i]==B[j]){ if(i==0||j==0); dp[i][j]=1; else dp[i][j] = dp[i - 1][j - 1] + 1; } 划分2 字符串 ADCDADB 和 ABDCDBABB 递推公式为: //二维数组遍历循环 从第二行,第二列开始遍历,第一行和第一列不遍历。 if(A[i-1]==B[j-1]){// dp

leetcode | 分类整理4(动态规划)

有些话、适合烂在心里 提交于 2020-02-15 15:14:06
递归和动态规划都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存了子问题的解,避免重复计算。 重点都是要找到转移方程 Fibonacci: 在上述方法中,我们使用 dp 数组,其中 dp[i]=dp[i-1]+dp[i-2]。可以很容易通过分析得出 dp[i]其实就是第 ii个斐波那契数。 Fib(n)=Fib(n−1)+Fib(n−2) 重点是确定pre1和pre2,以及最后要返回哪个 70. 爬楼梯(e) 198. 打家劫舍(e) 213. 打家劫舍2(m) 强盗在环形区抢劫 环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题: 在不偷窃第一个房子的情况下(即nums[1:]),最大金额是 p_1 在不偷窃最后一个房子的情况下(即 nums[:n−1]),最大金额是 p_2 综合偷窃最大金额: 为以上两种情况的较大值,即 max(p1,p2)。 public int rob(int[] nums) { if (nums == null || nums.length <= 0) { return 0; } if (nums.length == 1) { return nums[0]; } int n = nums.length; return Math.max(robHelper(nums,0

leetcode | 分类整理4(动态规划)

我是研究僧i 提交于 2020-02-15 15:01:51
递归和动态规划都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存了子问题的解,避免重复计算。 重点都是要找到转移方程 Fibonacci: 在上述方法中,我们使用 dp 数组,其中 dp[i]=dp[i-1]+dp[i-2]。可以很容易通过分析得出 dp[i]其实就是第 ii个斐波那契数。 Fib(n)=Fib(n−1)+Fib(n−2) 重点是确定pre1和pre2,以及最后要返回哪个 70. 爬楼梯(e) 198. 打家劫舍(e) 213. 打家劫舍2(m) 强盗在环形区抢劫 环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题: 在不偷窃第一个房子的情况下(即nums[1:]),最大金额是 p_1 在不偷窃最后一个房子的情况下(即 nums[:n−1]),最大金额是 p_2 综合偷窃最大金额: 为以上两种情况的较大值,即 max(p1,p2)。 public int rob(int[] nums) { if (nums == null || nums.length <= 0) { return 0; } if (nums.length == 1) { return nums[0]; } int n = nums.length; return Math.max(robHelper(nums,0

leetcode | 分类整理4(动态规划)

别等时光非礼了梦想. 提交于 2020-02-15 14:43:55
递归和动态规划都是将原问题拆成多个子问题然后求解,他们之间最本质的区别是,动态规划保存了子问题的解,避免重复计算。 重点都是要找到转移方程 Fibonacci: 在上述方法中,我们使用 dp 数组,其中 dp[i]=dp[i-1]+dp[i-2]。可以很容易通过分析得出 dp[i]其实就是第 ii个斐波那契数。 Fib(n)=Fib(n−1)+Fib(n−2) 重点是确定pre1和pre2,以及最后要返回哪个 70. 爬楼梯(e) 198. 打家劫舍(e) 213. 打家劫舍2(m) 强盗在环形区抢劫 环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题: 在不偷窃第一个房子的情况下(即nums[1:]),最大金额是 p_1 在不偷窃最后一个房子的情况下(即 nums[:n−1]),最大金额是 p_2 综合偷窃最大金额: 为以上两种情况的较大值,即 max(p1,p2)。 public int rob(int[] nums) { if (nums == null || nums.length <= 0) { return 0; } if (nums.length == 1) { return nums[0]; } int n = nums.length; return Math.max(robHelper(nums,0

动态规划:字符串编辑距离

亡梦爱人 提交于 2020-02-14 17:52:57
动态规划:字符串编辑距离 问题描述 有两个字符串A和B,现在将A经过三种变换可以得到B,即插入、删除和修改,这三种操作的代价分别为c0,c1和c2,问题就是A到B的变换所需要的最小代价是多少。 思路 典型的动态规划问题,娇哥曾经说过,字符串的问题大部分都是动态规划的问题,那么这个问题要怎么解决呢?动态规划问题首先定义状态,然后定义状态转移方程,然后确定初始状态和终止状态,然后就可以得到终止状态下的结果输出。 定义状态 我们定义状态 dp[i][j] 表示A从0-i和B从0-j这两段的最小编辑距离。状态的定义需要注意的是,状态只能和前面的情况有联系不能和后面的情况有联系。 转移方程 有了状态,那么就定义状态转移方程,状态转移方程的定义有时候会需要“找规律”,但是这道题的规律比较明显,很容易知道,当 A[i] == B[j] 的时候,从 dp[i-1][j-1] 到 dp[i][j] 是不需要任何编辑的,所以 dp[i-1][j-1] = dp[i][j] ,但是当他们不相等的时候,就需要考虑是插入、删除还是编辑的代价最短了,那么自然而然地有三种情况:插入,删除和编辑。插入的情况是什么? 插入是A在和B的前j-1个比,然后再在A的基础上进行插入一个字符,插入的字符是B的第j位,所以插入的代价是 dp[i][j-1]+c0 删除是A的前i-1个和B的j个比,因为把A删除了一个字符

动态规划:多边形游戏

南楼画角 提交于 2020-02-12 19:39:16
大家好,我是连人。本期继续讨论动态规划的问题。 已知一个n边的多边形,在n个顶点上都有一个整数,在n条边上都存在‘+’或‘*’号。 游戏开始时,撤掉一条边。剩下的就会变成由n个顶点,n-1条边所组成的链条。 将其中两个相邻的顶点按之间的运算符进行运算,这两个顶点和这条边被替换为运算结果,链条被削减为n-1个顶点,n-2条边。如此反复直到最后只剩下一个点。 多边形游戏的目的是找到最大的最后一个点。 我们首先来分析链条,假设这是一条顶点数为n,边数为n-1的链条。取位置为s的边。这条边将链条分为了[0:s]和[s+1:n-1]两条链条。 链条 最小值 最大值 [0:s] a b [s+1:n-1] c d 如果这条边是‘+’,那么问题就简单了,[0:n-1]的值一定在a+c到b+d之间。 如果这条边是‘*’,因为涉及到顶点含有负数的关系,所以只能将abcd两两 相乘,[0:n-1]的值是在min{ac,ad,bc,bd}和max{ac,ad,bc,bd}之间。 根据上面的分析,我们可以得知,多边形游戏也是有最优子结构的。 传统的做法是建立一个两层的二维数组m[ i ][ j ][ k ],代表以第i个点开头并且长为j的链条的最大值(k=1)和最小值(k=0)。 在最后寻找结果的时候只需要找m[ i ][ n ][ 1 ]中的最大值就可以了。 但是我不喜欢

动态规划-线性动态规划总结

浪尽此生 提交于 2020-02-12 03:48:34
线性规划个人理解就是给你一串数,可能是一个数列,可能是一个环,根据题意和数据递推出一个最优解。 核心过程就是能找到递推方程。 例如 求一个数列的 最长不 上升子序列的 长度。注意是长度不是序列! 数列:389 207 155 300 299 170 158 65 建一个dp数组,设这个数列储存在a数组 通常求什么,设什么,设dp[i]表示长度为i的串, 最长不 上升子序列的长度 dp[1]=a[1]=389 下一个数 a[2]=207 加在后面 dp[2]=207 下一个数a[3]=155 加在后面 dp[3]=155 下一个数 300 不能直接加在后面了,需要做选择 因为要最长不上升,可以知道末尾的数为数列最小数,我们希望最小数前面尽量大,这样是最好的情况 我们想要389 207 155 还是 389 300 155? 肯定是后面的,我们希望数下降的慢一些。 递推方式 if(这个数a[i]<dp[i]) 加在后面 dp[++len]=a[i] else 遍历dp[]数组,更换更优的值(注意这里只是更换!没有增加长度) 例题一 例题链接 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统

蓝桥杯:乘积最大II 动态规划解法

混江龙づ霸主 提交于 2020-02-12 00:33:59
蓝桥杯:乘积最大II 动态规划解法 因为数据不大,存在【 暴力解法 】 问题描述 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目: 设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。 同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子: 有一个数字串:312, 当N=3,K=1时会有以下两种分法: 3 * 12=36 31 * 2=62 这时,符合题目要求的结果是:31*2=62 现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。 输入格式 程序的输入共有两行: 第一行共有2个自然数N,K(6≤N≤40,1≤K≤6) 第二行是一个长度为N的数字串。 输出格式 输出所求得的最大乘积(一个自然数)。 样例输入 4 2 1231 样例输出 62 思路 问题: 求解在前 i 个数字中插入 j 个乘号得到的乘积最大值 状态定义: // dp[i][j]表示在前i个数字中插入j个乘号得到的乘积最大值 int dp [ ] [ ] ; 状态转移: 在前i个数中插入j个乘号,问题转换为: 在前k(下标 [1, k

动态规划解最长回文子序列并优化空间复杂度

徘徊边缘 提交于 2020-02-11 21:24:33
一个字符串有许多子序列,比如字符串abcfgbda,它的子序列有a、bfg、bfgbd,在这些子序列中肯定有回文字符串。现在要对任意字符串求其最长的回文子序列。注意,本文不是解决最长回文子串,回文子串是连续的,回文子序列是不连续的。 字符串abcfgbda的最长回文子序列为abcba,长度为5。 输入:包含若干行,每行有一个字符串,字符串由大小写字母构成,长度不超过100。 输出:对每个输入,输出一行,该行有一个整数,表示最长回文子序列的长度。 Example Input: a abcfgbda Output: 1 5 采用动态规划思想。 对任意字符串,如果头和尾相同,那么它的最长回文子序列一定是去头去尾之后的部分的最长回文子序列加上头和尾。如果头和尾不同,那么它的最长回文子序列是去头的部分的最长回文子序列和去尾的部分的最长回文子序列的较长的那一个。 设字符串为s,f(i,j)表示s[i..j]的最长回文子序列。 状态转移方程如下: 当i>j时,f(i,j)=0。 当i=j时,f(i,j)=1。 当i<j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2。 当i<j并且s[i]≠s[j]时,f(i,j)=max( f(i,j-1), f(i+1,j) )。 注意:如果i+1=j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2=f(j,j-1)+2=2