动态规划

01背包

回眸只為那壹抹淺笑 提交于 2020-01-25 17:39:14
动态规划( dynamic programming )算法是解决多阶段决策过程最优化问题的一种常用方法,难度比较大,技巧性也很强。利用动态规划算法,可以优雅而高效地解决很多贪婪算法或分治算法不能解决的问题。动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果,与贪婪算法不同的是,在贪婪算法中,每采用一次贪婪准则,便做出一个不可撤回的决策;而在动态规划算法中,还要考察每个最优决策序列中是否包含一个最优决策子序列,即问题是否具有最优子结构性质。 动态规划算法的有效性依赖于待求解问题本身具有的两个重要性质:最优子结构性质和子问题重叠性质。 1 、最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。 2 、子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中

快速上手leetcode动态规划题

我的梦境 提交于 2020-01-25 16:18:59
快速上手leetcode动态规划题 我现在是初学的状态,在此来记录我的刷题过程,便于以后复习巩固。 我leetcode从动态规划开始刷,语言用的java。 一.了解动态规划 我上网查了一下动态规划,了解到动态规划是“ 带有备忘录的递归 ”, 而大多数用来理解动态规划的例子都是 斐波那契数列 ,就是那个经典的递归式 f(i)=f(i-1)+f(i-2) ,f(1)=f(2)=1 那么我们就可以得到很多式子,比如求f(5): f(5)=f(4)+f(3); f(4)=f(3)+f(2); f(3)=f(2)+f(1); 然后我们就发现了重复的部分,在求f(5)和f(4)的时候都要求f(3),那么它们都要做一次f(3)的递归操作,来得到f(3)的值。 我想这是很不值得的,没必要同样的操作执行两遍。并且我们知道当f(n)的n比较大时,是很多重复的部分的,这也就意味着有很大的优化空间。 因此有了所谓的“ 备忘录 ”,也就是用一个 数组 来记录每个状态的结果,比如f(5)就是n为5时f(n)的状态。 这样的话,我们就可以在求f(n)的时候,先查看一下数组中是否记录了这一个状态的值,如果有,就直接从数组中拿,如果没有,就递归计算一下,再把这个值放到数组中去。这也是所谓的“ 以空间换时间 ”的思想。 int[] dp=new int[n+1];//dp[i]表示f(i)的值 在求f(x)时: if

Java动态规划

别说谁变了你拦得住时间么 提交于 2020-01-25 05:31:18
1. 介绍 动态规划典型的被用于优化递归算法,因为它们倾向于以指数的方式进行扩展。动态规划主要思想是将复杂问题(带有许多递归调用)分解为更小的子问题,然后将它们保存到内存中,这样我们就不必在每次使用它们时重新计算它们。 要理解动态规划的概念,我们需要熟悉一些主题: 什么是动态规划? 贪心算法 简化的背包问题 传统的背包问题 Levenshtein Distance LCS-最长的共同子序列 利用动态规划的其他问题 结论 本文所有代码均为 java 代码实现。 2. 什么是动态规划? 动态规划是一种编程原理,可以通过将非常复杂的问题划分为更小的子问题来解决。这个原则与递归很类似,但是与递归有一个关键点的不同,就是每个不同的子问题只能被解决一次。 为了理解动态规划,我们首先需要理解递归关系的问题。每个单独的复杂问题可以被划分为很小的子问题,这表示我们可以在这些问题之间构造一个递归关系。 让我们来看一个我们所熟悉的例子: 斐波拉契数列 ,斐波拉契数列的定义具有以下的递归关系: 注意:递归关系是递归地定义下一项是先前项的函数的序列的等式。 Fibonacci 序列就是一个很好的例子。 所以,如果我们想要找到斐波拉契数列序列中的第n个数,我们必须知道序列中第n个前面的两个数字。 但是,每次我们想要计算 Fibonacci 序列的不同元素时,我们在递归调用中都有一些重复调用,如下图所示

poj1845动态规划

心不动则不痛 提交于 2020-01-25 05:28:19
最长公共子序列 状态转移方程为dp[i][j] = dp[i-1][j-1]+1 s1[i]==s[j] = max{dp[i-1][j],dp[i][j-1]} s1[i]!=s2[j] #include <iostream> #include <cstring> #include <string> using namespace std; #define X 255 int dp[X][X]; string s1,s2; int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); while(cin>>s1>>s2) { memset(dp,0,sizeof(dp)); int len1 = s1.size(); int len2 = s2.size(); for(int i=1;i<=len1;i++) for(int j=1;j<=len2;j++) { if(s1[i-1]==s2[j-1]) dp[i][j] = dp[i-1][j-1]+1; else dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } cout<<dp[len1][len2]<<endl; } return 0; } 来源: https://www.cnblogs.com

动态规划poj1631--最长上升子序列

本小妞迷上赌 提交于 2020-01-25 05:25:23
题目大意: 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8). 你的任务,就是对于给定的序列,求出最长上升子序列的长度。 法一:O(n^2) 思路:转化成子问题:求以ak(k=1,2,3。。。N)为终点(即上升子序列中最右边的数)的最长上升子序列的长度。该问题只和数字的位置有关,因而序列中数的位置k就是“状态”,而状态“k“对应的值就是以ak作为终点的最长上升子序列的长度。假定maxlen(k)表示以ak作为终点的最长上升子序列的长度,则: maxlen(1)=1; maxlen(k)=max{maxlen(i):1<i<k且ai<ak且k!=1}+1 这个状态转移方程的思想是:maxlen(k)的值就是在ak左边,终点小于ak,且长度最大的那个上升子序列的长度再加1.因为ak左边任何终点小于ak的子序列加上ak后就能形成一个更长的上升子序列。 以下是代码: #include

动态规划与贪心的区别

[亡魂溺海] 提交于 2020-01-24 20:40:25
转自 : http://hi.baidu.com/abcdcamey/item/0d1d6746c9ef4616896d10ac 动态规划和贪心算法的区别 动态规划和贪心算法都是一种递推算法 均有局部最优解来推导全局最优解 不同点: 贪心算法: 1.贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留。 2.由(1)中的介绍,可以知道贪心法正确的条件是:每一步的最优解一定包含上一步的最优解。 动态规划算法: 1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解 2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解 3.边界条件:即最简单的,可以直接得出的局部最优解 ============================================================================== 贪心算法与动态规划 贪心法的基本思路: 从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。 该算法存在问题: 1. 不能保证求得的最后解是最佳的; 2. 不能用来求最大或最小解问题; 3. 只能求满足某些约束条件的可行解的范围。实现该算法的过程:

Codevs_1048_石子归并_(动态规划)

醉酒当歌 提交于 2020-01-24 15:18:31
描述 http://codevs.cn/problem/1048/ 1048 石子归并 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。 输入描述 Input Description 第一行一个整数n(n<=100) 第二行n个整数w1,w2...wn (wi <= 100) 输出描述 Output Description 一个整数表示最小合并代价 样例输入 Sample Input 4 4 1 1 4 样例输出 Sample Output 18 分析 状态方程:dp[i][j]表示把区间[i,j]合并所需要的最小花费. 状态转移方程:dp[i][j]=dp[i][k]+dp[k+1][j]+(w[i]+w[i+1]+...+w[j-1]+w[j]). 可见先要求出小区间,才能求大区间. 有两种做法: 1.先求出所有长度为2的区间,再求出所有长度为3的区间...最后求出长度为n的区间. 2.先求出区间右端点是2的区间,再求出区间右端点时3的区间...最后求出区间右端点是n的区间. 注意: 1.解法1中的小区间都是求过的

L2-008 最长对称子串 (25分)

混江龙づ霸主 提交于 2020-01-24 14:00:07
对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定 Is PAT&TAP symmetric? ,最长对称子串为 s PAT&TAP s ,于是你应该输出11。 输入格式: 输入在一行中给出长度不超过1000的非空字符串。 输出格式: 在一行中输出最长对称子串的长度。 输入样例: Is PAT&TAP symmetric? 输出样例: 11思路:本题可以有多种方法来解决,动态规划,马拉车等等,但是我更擅长动态规划来解决此题,本题定义一个动态规划数组dp[i][j],表示的意义为字符串从i-j是否为回文串,首先应该确定数组的边界,当字串长度为1时一定为会文串,当子串长度为2时只要判断s[i]是否等于s[j]就可以判断i-j是否为回文串,当字串的长度大于等于2时知道判定s[i]==s[j]和dp[i+1][j-1]>0就可判断是否为回文串,所以本题的状态公式为:      1 i==jdp[i][j]= 2 i-j==1&&str[i]==str[j]    dp[j+1][i-1]+2 str[i]==str[j]&&dp[j+1][i-1]>0代码: /** * */ package com.xingbing.tianti; import java.io.BufferedReader; import java.io.IOException; import java.io

程序员必须掌握的核心算法有哪些?

故事扮演 提交于 2020-01-23 18:21:36
由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是零散的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过不错的文章给大家。大家也可以留言区补充。 一、算法最最基础 1、时间复杂度 2、空间复杂度 一般最先接触的就是时间复杂度和空间复杂度的学习了,这两个概念以及如何计算,是必须学的,也是必须最先学的,主要有最大复杂度、平均复杂度等,直接通过博客搜索学习即可。 文章推荐: 算法分析神器—时间复杂度 二、基础数据结构 1、线性表 列表(必学) 链表(必学) 跳跃表(知道原理,应用,最后自己实现一遍) 并查集(建议结合刷题学习) 不用说,链表、列表必须,不过重点是链表。 三分钟基础数据结构:如何轻松手写链表? 以后有面试官问你「跳跃表」,你就把这篇文章扔给他 2、栈与队列 栈(必学) 队列(必学) 优先队列、堆(必学) 多级反馈队列(原理与应用) 特别是优先队列,再刷题的时候,还是经常用到的,队列与栈,是最基本的数据结构,必学。可以通过博客来学习。相关文章: 三分钟基础知识:什么是栈?

动态规划进阶

拟墨画扇 提交于 2020-01-23 16:45:02
理论解析 动态规划其实就是记住之前问题的答案,然后利用之前问题的答案来分析并解决当前问题,这里面有两个非常重要的步骤,就是 拆解问题 和 定义状态 。 这次来针对具体的一类动态规划问题,矩阵类动态规划问题,来看看针对这一类问题的思路和注意点。 矩阵类动态规划,也可以叫做坐标类动态规划,一般这类问题都会给你一个矩阵,矩阵里面有着一些信息,然后你需要根据这些信息求解问题。 一般来说,在思考这类动态规划问题的时候,我们只需要思考当前位置的状态,然后试着去看当前位置和它邻居的递进关系,从而得出我们想要的递推方程,这一类动态规划问题,相对来说比较简单 不同路径 说明: m 和 n 的值均不超过 100。 题目解析: 问题拆解:题目中说了,每次移动只能是向右或者是向下,矩阵类动态规划需要关注当前位置和其相邻位置的关系,对于某一个位置来说,经过它的路径只能从它上面过来,或者从它左边过来,因此,如果需要求到达当前位置的不同路径,我们需要知道到达其上方位置的不同路径,以及到达其左方位置的不同路径 状态定义:矩阵类动态规划的状态定义相对来说比较简单,只需要看当前位置即可,问题拆解中,我们分析了当前位置和其邻居的关系,提到每个位置其实都可以算做是终点,状态表示就是 “ 从起点到达该位置的不同路径数目 ” 递推方程:dp[i][j]=dp[i][j-1]+dp[i-1][j] 实现