动态规划

有趣的动态规划(golang版本)

拟墨画扇 提交于 2019-12-06 21:25:31
多年前就听过这个动态规划,最近在复习常用算法的时候才认真学习了一下,发现蛮有意思,和大家安利一波。 定义: 准确来说,动态规划师吧一个复杂问题分解成若干个子问题,并且寻找最优子问题的一种思想,而不是一种特定的算法。 听上去和我们常用的递归有点类似,但是注意:其中子问题的解被重复使用。也就是利用这个特性,我们可以把一个复杂的问题抽象转换成一个简单二维表来进行推演。 动态规划的解题关键在于: 1.根据问题可能性进行拆分。 从最简单的情况下进行分析,从下往上逐步分析。 2.找到状态转移方程式,保存最优解。 方程式其实就是在满足某个条件下的递推通项公式,同时也要注意条件范围和边界处理。 最有名的是背包问题:将N种类型的物件放到一个容量为M的背包里面,寻找最优解。 一般来说可以用暴力枚举的方式去算近似最优,但是从空间复杂度和时间复杂度来看使用动态规划更好,因为每一步的结果会保存下来给下一步计算使用,节约了不少时间消耗,最终算法性能极高。 下面举一个典型的例子,来自牛客网的一道"凑整题": 给你六种面额 1、5、10、20、50、100 元的纸币,假设每种币值的数量都足够多,编写程序求组成N元(N为0~10000的非负整数)的不同组合的个数。 仔细分析后发现,这是一个用不同类型的面额组合拼凑固定金额的组合最优解问题。由于N为0 ~ 10000的非负数,我们可以假设N取10来分析。 分析结果如图

HMM隐马尔可夫模型详解

折月煮酒 提交于 2019-12-06 14:14:24
1 隐马尔可夫模型HMM 隐马尔科夫模型(Hidden Markov Model,以下简称HMM)是比较经典的机器学习模型了,它在语言识别,自然语言处理,模式识别等领域得到广泛的应用。 当然,随着目前深度学习的崛起,尤其是 RNN , LSTM 等神经网络序列模型的火热,HMM的地位有所下降。 但是作为一个经典的模型,学习HMM的模型和对应算法,对我们解决问题建模的能力提高以及算法思路的拓展还是很好的。 1.1 什么样的问题需要HMM模型 首先我们来看看什么样的问题解决可以用HMM模型。 使用HMM模型时我们的问题一般有这两个特征: 1)我们的问题是基于序列的,比如时间序列,或者状态序列。 2)我们的问题中有两类数据,一类序列数据是可以观测到的,即观测序列;而另一类数据是不能观察到的,即隐藏状态序列,简称状态序列。 有了这两个特征,那么这个问题一般可以用HMM模型来尝试解决。这样的问题在实际生活中是很多的。比如:我现在在打字写博客,我在键盘上敲出来的一系列字符就是观测序列,而我实际想写的一段话就是隐藏序列,输入法的任务就是从敲入的一系列字符尽可能的猜测我要写的一段话,并把最可能的词语放在最前面让我选择,这就可以看做一个HMM模型了。再举一个,我在和你说话,我发出的一串连续的声音就是观测序列,而我实际要表达的一段话就是状态序列,你大脑的任务

动态规划&&状压

北城余情 提交于 2019-12-06 14:07:21
目录 一、动态规划 案例一、简单的一维 DP 二、状态压缩 UVA1099 一、动态规划 动态规划,无非就是利用 历史记录 ,来避免我们的重复计算。而这些 历史记录 ,我们得需要一些 变量 来保存,一般是用 一维数组 或者 二维数组 来保存。下面我们先来讲下做动态规划题很重要的三个步骤, 如果你听不懂,也没关系,下面会有很多例题讲解,估计你就懂了。之所以不配合例题来讲这些步骤,也是为了怕你们脑袋乱了 第一步骤 :定义 数组元素的含义 ,上面说了,我们会用一个数组,来保存历史数组,假设用一维数组 dp[] 吧。这个时候有一个非常非常重要的点,就是规定你这个数组元素的含义,例如你的 dp[i] 是代表什么意思? 第二步骤 :找出 数组元素之间的关系式 ,我觉得动态规划,还是有一点类似于我们高中学习时的 归纳法 的,当我们要计算 dp[n] 时,是可以利用 dp[n-1],dp[n-2].....dp[1],来推出 dp[n] 的,也就是可以利用 历史数据 来推出新的元素值,所以我们要找出数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],这个就是他们的关系式了。而这一步,也是最难的一步,后面我会讲几种类型的题来说。 学过动态规划的可能都经常听到 最优子结构 ,把大的问题拆分成小的问题,说时候,最开始的时候,我是对 最优子结构 一梦懵逼的。估计你们也听多了

洛谷 P1005 动态规划

偶尔善良 提交于 2019-12-06 13:50:21
Problem Description 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n \times mn×m的矩阵,矩阵中的每个元素a_{i,j}a i,j 均为非负整数。游戏规则如下: 每次取数时须从每行各取走一个元素,共nn个。经过mm次后取完矩阵内所有元素; 每次取走的各个元素只能是该元素所在行的行首或行尾; 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值\times 2^i×2 i ,其中ii表示第ii次取数(从11开始编号); 游戏结束总得分为mm次取数得分之和。 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。 Input 输入文件包括n+1n+1行: 第11行为两个用空格隔开的整数nn和mm。 第2\backsim n+12∽n+1行为n \times mn×m矩阵,其中每行有mm个用单个空格隔开的非负整数。 Output 输出文件仅包含11行,为一个整数,即输入矩阵取数后的最大得分。 Sample Input 2 3 1 2 3 3 4 2 Sample Output 82 Analysis of ideas 设 k=m-(R-L) ,可以得到状态转移方程: f[L][R]=max(num[L]*p[k]+dp(L+1,R),dp(L,R-1)+num[R]*p[k]) for(int len=0;len<

动态规划之仓鼠吃豆子

蓝咒 提交于 2019-12-06 13:18:50
动态规划之仓鼠吃豆子 【题目】m * n的方格上,每一格存放一定数量的豆子,一只仓鼠从左下角一直吃到右上角,但仓鼠只能向右或向上走。那么仓鼠做多可以吃多少豆子? 【思路】因为仓鼠只能向左或者向上走,那么到达任意一点的豆子数量由两部分组成:该点本身的豆子beans(x,y),max{到达左边的豆子总数path(x-1,y), 到达下方的豆子总数path(x, y-1)}。 于是得到到达任意一点的豆子总数的公式P(x,y) = F(x,y) + max(P(x-1, y), P(x, y-1))。计算并记录每个点的豆子总数,同时为了避免重复计算,将计算的中间结果存储在path数组中。 【注意】 因为矩阵原点在左上角,需要对公式进行变换。P(x,y) = F(x,y) + max(P(x+1, y), P(x, y-1)); 注意边界值,这里需要注意三点,左下角的点、左边界、下边界。 #include <stdio.h> #include <stdlib.h> int max(int a, int b) { if (a > b) return a; return b; } int main() { int m, n; int i, j; int **beans; int **path; scanf("%d %d", &m, &n); /* m * n矩阵 */ beans = (int*

前置内容1:算法与数据结构

我是研究僧i 提交于 2019-12-06 08:42:38
信息学竞赛的主要考点就是算法与数据结构。 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。 简单来说,算法用于解决一个具体的问题,应该具有几个性质:确切性,有限性,输入输出,可行性。 也就是说,一个算法应该首先是确定的,而不是模棱两可的;其次是可以在有限的时间和步数内完成;另外需要有输入和输出(输入可以没有,但输出必然需要);所有的基本操作都是可以完成的。 属于OI范围的算法主要包括: 基本算法:包括枚举,模拟,贪心,二分,排序等。它们是其他算法或数据结构的基础; 搜索算法:包括深度优先搜索(DFS),广度优先搜索(BFS)及其优化。搜索是比较接近暴力的算法,但是又有很多优化型内容,例如迭代加深搜索(ID-DFS),A*算法等,在NOIP普及组和提高组中非常重要; 动态规划(DP):包括线性动态规划,多维动态规划,树形动态规划,状态压缩动态规划,图论动态规划等,还有一些拓展的类型,如期望DP,插头DP,数位DP,动态DP等。动态规划是较难的算法,无论是什么等级的比赛中动态规划都是极其重要的; 图论算法:包括最短路算法(SP),最小生成树(MST),拓扑排序,无向图的割边和割点,有向图的强连通分量(SCC),二分图匹配

动态规划--矿工挖矿

回眸只為那壹抹淺笑 提交于 2019-12-06 05:43:11
动态规划三要素:边界、最优子问题、状态转移方程; 问题描述:现有10个矿工,5个金矿,每个金矿有对应金子和需要开采的人数,问你最多能够获得多少金子? 这是一个典型的动态规划问题,动态规划的核心是如何将问题转换为重叠的子问题,并且写出状态转移方程。 首先我们定义相应的参数: 矿工个数:n=10 金矿个数:w=5 金子数量:g=[400,500,200,300,350] 需要人数:p=[5,5,3,4,4] p[i]代表挖了第i个金矿所需人数,g[i]代表挖了第 i个金矿得到的金子数。令F(n,w)表示n个人挖w个金矿能够得到的最大金子数。 当n<p[i]时,也就是说挖第i个金矿的人数不够,那么此时可以获得的最大金子数就是挖第i-1个金矿时的金子: F(n,w)=F(n,w-1) 那么我们当n>p[i]时,有以下方程: F(n,w)=max(F(n,w-1),F(n-p[i],w-1)+g[i]) 表示n个人挖w个金矿能够得到的最大金子数=最大值(n个人挖w-1个金矿,((n-p[i])个人挖w-1个金矿)+g[i])) 最终代码: n=10 w=5 g=[400,500,200,300,350] p=[5,5,3,4,3] def goldMining(n,w,g,p): #初始化数组,用于存储信息,注意为了更好计算,共有11列,第一列作为辅助位 dp = [[0 for _ in

洛谷——动态规划的背包问题P1060

血红的双手。 提交于 2019-12-06 04:17:40
2019-11-30 10:08:41 #include<bits/stdc++.h> #include <stdlib.h> #include <stdio.h> using namespace std; int w[30],v[30],f[50000]; int n,m; int main(){ cin>>m>>n; for(int i=1;i<=n;++i){ cin>>v[i]>>w[i]; w[i] *= v[i]; } //01背包 for(int i=1;i<=n;++i){ for(int j=m;j>=v[i];j--){ if(j>=v[i]){ f[j] = max(f[j],f[j-v[i]]+w[i]); } } } cout<<f[m]<<endl; system("pause"); return 0; } 来源: https://www.cnblogs.com/JasonPeng1/p/11961475.html

洛谷——动态规划

谁说我不能喝 提交于 2019-12-06 04:17:19
2019-11-30 10:04:17 #include<bits/stdc++.h> #include <stdlib.h> #include <stdio.h> using namespace std; int w[30],v[30],f[50000]; int n,m; int main(){ cin>>m>>n; for(int i=1;i<=n;++i){ cin>>v[i]>>w[i]; w[i] *= v[i]; } //01背包 for(int i=1;i<=n;++i){ for(int j=m;j>=v[i];j--){ if(j>=v[i]){ f[j] = max(f[j],f[j-v[i]]+w[i]); } } } cout<<f[m]<<endl; system("pause"); return 0; } 来源: https://www.cnblogs.com/JasonPeng1/p/11961459.html

动态规划

白昼怎懂夜的黑 提交于 2019-12-06 03:44:47
 这个思路来源于搞了动态规划几十年(也算是理论奠基人之一了)的Dimitri Bertsekas,他所称之为Abstract Dynamic Programming Models。动态规划是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。 动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。 动态规划问题满足三大重要性质 一、抽象模型 ¶ 定义:两个集合 S,A ;策略映射 mu ;两个算子 T_mu,T 本节我们定义为了准确描述动态规划模型必不可少的5个符号。 考虑 S 和 A 为两个集合,前者我们认为是包含所有状态(state)的集合,后者我们认为是包含所有控制(control,或者action)的集合。对任意 sin S ,定义 A(s)subset A 为针对状态 s 的可行控制集。然后我们再对任意 sin S