动态规划

动态规划——B 最大高度问题

我们两清 提交于 2019-12-30 01:35:34
B - LIS Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Submit Status Description 一组研究人员正在设计一项实验,以测试猴子的智商。他们将挂香蕉在建筑物的屋顶,同时,提供一些砖块给这些猴子。如果猴子足够聪明,它应当能够通过合理的放置一些砖块建立一个塔,并爬上去吃他们最喜欢的香蕉。 研究人员有n种类型的砖块,每种类型的砖块都有无限个。第i块砖块的长宽高分别用xi,yi,zi来表示。 同时,由于砖块是可以旋转的,每个砖块的3条边可以组成6种不同的长宽高。 在构建塔时,当且仅当A砖块的长和宽都分别小于B砖块的长和宽时,A砖块才能放到B砖块的上面,因为必须留有一些空间让猴子来踩。 你的任务是编写一个程序,计算猴子们最高可以堆出的砖块们的高度。 Input 输入文件包含多组测试数据。 每个测试用例的第一行包含一个整数n,代表不同种类的砖块数目。n<=30. 接下来n行,每行3个数,分别表示砖块的长宽高。 当n= 0的时候,无需输出任何答案,测试结束。 Output 对于每组测试数据,输出最大高度。格式:Case 第几组数据: maximum height = 最大高度 Sample Input 1 10 20 30 2 6 8 10 5 5 5 7 1 1 1 2

动态规划及其应用

泄露秘密 提交于 2019-12-28 20:26:47
动态规划 杭电oj做到了最大子序列和,自己的换了好多方法都超时了,网上一查需要用到动态规划,趁此机会学习一下动态规划 但是感觉动态规划有点像这个递归哈哈哈哈 1. 动态规划 ,就是利用历史记录来避免计算的重复,而这些历史记录我们需要一些变量来保存,一般用到一维数组还有二维数组来保存 2. 三个步骤 (1) 定义数组元素的含义 ,例如你的dp【i】代表的什么含义 (2) 找出数组元素之间的关系式 ,有点类似高中所学的数学归纳法,都是通过已知元素来推未知元素 (3) 找出初始值 ,学过数学归纳法的都知道,虽然我们知道了数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],我们可以通过 dp[n-1] 和 dp[n-2] 来计算 dp[n], 但是,我们得知道初始值啊,例如一直推下去的话,会由 dp[3] = dp[2] + dp[1]。而 dp[2] 和 dp[1] 是不能再分解的了,, 所以我们必须要能够直接获得 dp[2] 和 dp[1] 的值而这,就是所谓的初始值。由了初始值,并且有了数组元素之间的关系式 ,那么我们就可以得到 dp[n] 的值了,而 dp[n] 的含义是由你来定义的,你想求什么,就定义它是什么,这样,这道题也就解出来了。 3. 小青蛙跳台阶 问题描述,**一只青蛙一次可以跳上一级台阶,也可以跳上二级台阶

【动态规划】Codeforce 1282B2 K for the Price of One (Hard Version)

和自甴很熟 提交于 2019-12-28 14:34:08
保研之后的休闲时光 一、 题目大意 题目的大致意思如下,有一家商店举办活动,可以用一个商品的价钱购买走K件商品,需要付出的价钱是这K件商品的最大值。题目给定你具有的金钱p,商品数n和商品价格数组a,要你求解最多能买多少件商品,规定每一件商品仅能购买一次。 二、题目思路以及AC代码 这题是上一道题 Codeforce 1282 B1 的一个困难版本,说是困难,其实就是用时间把暴力的方法给卡了… 我做题就很循规蹈矩,上一道题正好是暴力解决的。 好,下面来说一下这道题的思路,其实会了暴力的方法,这道题无非就是用动态规划去去除一些暴力方法的重复运算,正好两道题对比可以看出时间效率上的显著提高,那么如何进行动态规划呢? 考虑我们要购买第i件商品时的所有可能情况。为了方便说明,这里借用我定义的几个数组。  rest数组:rest[i],表示当前还剩多少钱  dp数组:dp[i],表示截至看到第i件商品,用所有的钱p最多可以购买多少件。  a数组:a[i],表示第i件商品的价钱   下面就是所有可能遇到的情况,当遇到第i件商品的时候,我们有两种选择: ① 用金钱a[i]购买这件商品,并且同时取走相邻小于a[i]的k件商品 ② 用金钱a[i]购买这件商品,且仅取走这件商品 这里要注意,题目要求只有这两种情况,不存在你购买商品后拿走小于k件商品。 所以当你遇到第i件商品的时候

区间动态规划

别等时光非礼了梦想. 提交于 2019-12-27 03:02:49
区间 DP是指在一段区间上进行的一系列动态规划。 对于区间 DP 这一类问题,我们需要计算区间 [1,n] 的答案,通常用一个二维数组 dp 表示,其中 dp[x][y] 表示区间 [x,y]。 有些题目,dp[l][r] 由 dp[l][r−1] 与 dp[l+1][r] 推得;也有些题目,我们需要枚举区间 [l,r] 内的中间点,由两个子问题合并得到,也可以说 dp[l][r] 由 dp[l][k] 与 dp[k+1][r] 推得,其中 l≤k<r。 对于长度为 n 的区间 DP,我们可以先计算 [1,1],[2,2]…[n,n] 的答案,再计算 [1,2],[2,3]…[n−1,n],以此类推,直到得到原问题的答案。 一道经典例题: NOI 1995 石子合并 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分. 输入输出格式 输入格式: 数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数. 输出格式: 输出共2行,第1行为最小得分,第2行为最大得分. 输入输出样例 输入样例#1: 4 4 5 9 4 输出样例#1: 43 54 分析 我们利用动态规划的思想

动态规划---区间dp

核能气质少年 提交于 2019-12-27 02:53:16
今天写内网题,连着写了两道区间dp,这里就总结一下。 区间dp思想主要是先枚举f[i][j]中的i,再枚举j,再枚举一个1~j之间的变量k,一般是f[i][j] = max(f[i][j],f[i][k] + f[k][j]);(石子合并) 但是今天遇到的两个都不是这样的。 第一题,复制书稿,洛谷P1282。猜到是区间dp了,但是没写出来。后来看了一下,f[i][j]代表前i个人写到j本书,枚举k为第i个人从第k本书开始写。这样转移方程就很好想了。f[i][j] = min(f[i][j],max(f[i - 1][l],a[l - 1] + a[l] + a[l + 1] + ... + a[j]),这样复杂度有点高,所以后半部分用前缀和来维护就行了。 代码: #include<cstdio> #include<iostream> #include<cstring> using namespace std; int f[510][510]; int a[510],m,n,sum[510]; void print(int x, int Ans) { if(!x) return; for(int i=x; i>=0; i--) { if(sum[x] - sum[i-1] > Ans || !i) { print(i, Ans); printf("%d %d\n", i+1, x);

区间动态规划

对着背影说爱祢 提交于 2019-12-27 02:48:49
石子合并 现在有n块石头,多多要把这n个石头进行合并 每一次合并,多多可以把 相邻 两 个石子合并到一起,得分等于两个石头的重量之和。 可以看出,所有的石子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共的得分等于每次合并石头质量之和。 求得分最少是多少,最多是多少? (n<=100) 样例输入#1 4 4 4 5 9 样例输出#1 4354 样例解释#1 得分最大情况: 第一步,多多先把5和9合并,得分为14,各石子数变成:4 4 14 第二步,多多先把14和4合并,得分为18,各石子变成:4 18 第三步,多多不得不把4和18合并,得分为22,,只剩下一堆石子:22 各得分和为54,可以证明分数最大为54; 得分最小情况: 第一步,多多先把4和4合并,得分为8,各石子变成:8 5 9 第二步,多多先把8和5合并,得分为13,各石子变成:13 9 第三步,多多不得不把13和9合并,得分为22,,只剩下一堆石子:22 各得分和为43,可以证明分数最小为43; 【题解】 可以知道,这道题是经典的区间dp问题;我们设dp[i][j]为i~j中操作的最大得分(以最大为例) 这里的sum[i,j]表示原数列中的i+i+1+.......+j的值,我们可以通过O(n^2)的预处理来求出sum 第0阶段:dp[1][1],dp[2][2],dp[3][3],dp[4][4]

动态规划算法------背包问题

末鹿安然 提交于 2019-12-27 02:26:04
1、动态规划与分治法的相似点:都是将待求问题分解成若干个子问题,先求解出这些子问题,然后从子问题的解得到原问题的解 不同点:适合用动态规划求解的问题,经分解得到的子问题一般不是互相独立的。 2、动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中可能有许多可行解,每一个解都对应一个值,希望找到具有最优值的解。 3、动态规划算法的有效性依赖于最优子结构 和 子问题重叠 最优子结构 指的是问题的最优解 包含了 其子问题的最优解,使得程序能以自底向上的方式递推地从子问题的最优解逐步 构造出 整个问题的最优解 子问题重叠 指的是对某些子问题重复求解多次,动态规划能存储这些解。 4、解决动态规划的问题的手段: 第一:递归:先自上到底 再 自底到上 优势:正着由大规模问题推向小规模问题,容易想 劣势:但是效率低。 第二:迭代递推: 直接自底向上 优势 效率高 劣势:不好想 5、写动态规划算法,最重要的是要找到动态规划递推式 0-1背包问题,如果有n个物品,它们的重量分别为w1,w2......wn,价值分别为v1,v2....vn,现有一个负重为k的背包,要求选择物品装入背包, 使背包中物体总价值最大。 1、背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] }//前者表示放入第i件物品(如果超出重量价值为0)

《算法导论》第15章 动态规划总结

青春壹個敷衍的年華 提交于 2019-12-27 02:22:23
1、基本概念   动态规划是通过组合子问题的解而解决整个问题的,通过将问题分解为相互不独立(各个子问题包含有公共的子问题,也叫重叠子问题)的子问题,对每个子问题求解一次,将其结果保存到一张辅助表中,避免每次遇到各个子问题时重新计算。动态规划通常用于解决最优化问题,其设计步骤如下: (1)描述最优解的结构。 (2)递归定义最优解的值。 (3)按自底向上的方式计算最优解的值。 (4)由计算出的结果构造出一个最优解。   第一步是选择问题的在什么时候会出现最优解,通过分析子问题的最优解而达到整个问题的最优解。在第二步,根据第一步得到的最优解描述,将整个问题分成小问题,直到问题不可再分为止,层层选择最优,构成整个问题的最优解,给出最优解的递归公式。第三步根据第二步给的递归公式,采用自底向上的策略,计算每个问题的最优解,并将结果保存到辅助表中。第四步骤是根据第三步中的最优解,借助保存在表中的值,给出最优解的构造过程。 动态规划与分治法之间的区别: (1) 分治法是指将问题分成一些独立的子问题,递归的求解各子问题。 (2) 动态规划适用于这些子问题不是独立的情况,也就是各子问题包含公共子问题。 2、动态规划基础   什么时候可以使用动态规范方法解决问题呢?这个问题需要讨论一下,书中给出了采用动态规范方法的最优化问题中的两个要素:最优子结构和重叠子结构。 1)最优子结构  

递归和递推 && 动态规划算法

风流意气都作罢 提交于 2019-12-27 02:18:56
借鉴:http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741374.html 动态规划算法: 一、算法思想: 将待求解的问题分解成若干个子问题,并存储子问题的解而避免计算重复的子问题,并由子问题的解得到原问题的解。 l动态规划算法通常用于求解具有某种最优性质的问题。 l动态规划算法的基本要素:最优子结构性质和重叠子问题。 1、l最优子结构性质: 问题的最优解包含着它的子问题的最优解 。即不管前面的策略如何,此后的决策 必须是基于当前状态 (由上一次决策产生)的最优决策。 2、重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些问题被反复计算多次。对每个子问题只解一次,然后将其解保存起来,以后再遇到同样的问题时就可以直接引用,不必重新求解 二、特征: 1. 动态规划一般解决最值(最优,最大,最小,最长……)问题; 2. 动态规划解决的问题一般是离散的,可以分解(划分阶段)的; 3. 动态规划解决的问题必须包含最优子结构,即可以由(n-1)的最优推导出n的最优。 三、动态规划算法的4个步骤: 1. 刻画最优解的结构特性. (一维,二维,三维数组) 将(1,2,3,4,5.....i-1,i)状态的值存到数组中 2. 递归的定义最优解. (状态转移方程) 3. 以自底向上的方法来计算最优解. 4.

动态规划--背包

懵懂的女人 提交于 2019-12-26 22:35:34
1. 01背包: 有 N 件物品和一个容量为 V 的背包。第 i 件物品的费用是 c[i],价值是 w[i]。求解将哪些物品装入背包可使价值总和最大。    对于这类问题我们我们定义f[i][j]表示在前i个物品中选总容量为j所能得到的最大价值为多少于是我们状态转移便是这样 f[i][j]=max(f[i][j],f[i-1][j-w[i]]+v[i]); int f[N][M]; void work() { memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) for(int j=w[i];j<=m;j++) f[i][j]=max(f[i][j],f[i-1][j-w[i]]+v[i]); for(int i=1;i<=m;i++) ans=max(f[n][i],ans); printf("%d\n",ans); }   这样一来,我们的时间复杂度就是O(nm),空间复杂度为O(nm),但我们发现f[i]的值只与f[i-1]有关,此时我们可以用滚动数组来优化空间到O(m),为f[j]=max(f[j],[j-w[i]]+v[i]);此时我们的j就要倒序枚举,因为j只会从比它小的j那转移。 int f[M]; void work() { memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) for(int