动态规划

leetcode动态规划--基础题

为君一笑 提交于 2019-12-09 23:10:57
跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 思路 根据题目意思,最大跳跃距离,说明可以跳0--nums[i]的距离 可以把跳跃看成走nums[i]步,如果能走到下一位置则可以 加油 获取更多的步数(nums[j]步),但是不能累加 那么只需扫一遍nums数组,更新剩余能跳的距离(注意不能累加,只能取最大!) 到终点之前判断是否有剩余步骤即可 代码 class Solution { public: bool canJump(vector<int>& nums) { if(nums.size()==0)return false; int cur=nums[0]; for(int i=1;i<nums.size();++i){ if(cur<=0){ return false; } cur--; cur=std::max(cur,nums[i]); } return true; } }; 不同路径 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 问总共有多少条不同的路径? 思路 当前位置可以来自上方或者左边 令dp[i][j

初学ACM

可紊 提交于 2019-12-09 20:53:43
题目重述: 问题描述 要求找出具有下列性质数的个数(包含输入的自然数n): 先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理: 1. 不作任何处理; 2. 在它的左边加上一个自然数,但该自然数不能超过原数的一半; 3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止. 输入 一个自然数n 输出 一个数,表示满足条件的数的个数 样例输入 6 样例输出 6 提示 样例说明:满足条件的数是6,16,26,126,36,136 假设不考虑重复的情况,那么采用下面公式即可: 只需要一个数组,很容易写出下面这个程序: #include <iostream> #include <cstring> using namespace std; int ans[100005]; int main() { int n; cin>>n; for(int i=0; i<=n; i++) ans[i] = 1; for(int i=2; i<=n; i++) { for(int j=1; j<=i/2; j++) ans[i] += ans[j]; } cout<<ans[n]<<endl; return 0; } 这个程序已经可以AC南京邮电大学OJ的测试数据了,但却过不去FOJ 1207,原因是没有考虑重复生成的情况。 下面我们来看一个重复生成的情况: 60-(添加24)

[动态规划]石子合并问题

烂漫一生 提交于 2019-12-09 09:18:52
https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/3016/pid/1729 石子合并问题 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。 对于给定n堆石子,计算合并成一堆的最小得分和最大得分。 Input 输入数据的第1行是正整数n,1≤n≤100,表示有n堆石子。第二行有n个数,分别表示每堆石子的个数。 Output 输出数据有两行,第1行中的数是最小得分,第2行中的数是最大得分。 Sample Input 4 4 4 5 9 Sample Output 43 54 算法考试考完了(题目有点简单侥幸AK..),但这个问题当时困扰我了很久,网上解答的很模糊,因此还是在这里记录一下吧。这题的难点是:如果将环形转换为直线(直线的网上有很多解答,这里不做赘述)。其核心思想就是:通过将数量变为 2n-1 来转换成直线问题。当时看到这几行字困惑了很久,一直不太理解,但之后画图就懂了。 1.

动态规划之最长公共子序列问题(LCS)

你离开我真会死。 提交于 2019-12-08 11:33:20
问题描述 输入: X = { x 1 , x 2 , … … , x m } //--> Y = { y 1 , y 2 , … … , y m } //--> 输出: Z=X和Y的最长公共子序列 说明: 如果: X = { A , B , C } , Y = { A , C , D } //--> ,则X和Y的最长公共子序列 Z = { A , C } //--> 结构分析 我们将一个序列如 X //--> 的前 i //--> 个元素定义: X i //--> ,则有 X i = { x 1 , x 2 , … … , x i } //--> 我们将 X Y //--> 的最长公共子序列记为 L C S X Y //--> 我们将 X //--> 的前 i //--> 个和 Y //--> 的前 j //--> 个元素的最长公共子序列记为 L C S X i Y j //--> 我们看一下如下的关系: 我们假设 L C S X m Y n = Z = { z 1 , … … , z k } //--> 我们就可以知道 L C S X m − 1 Y n − 1 //--> 和 L C S X m Y n //--> 之间的关系为: (1)当 X m = Y n //--> 时: L C S X m Y n = L C S X m − 1 Y n − 1 + < x m = y

教你彻底理解动态规划——扔鸡蛋问题 Drop Eggs2

我的未来我决定 提交于 2019-12-08 11:33:05
有一个 n 层的建筑。如果一个鸡蛋从第 k 层及以上落下,它会碎掉。如果从低于这一层的任意层落下,都不会碎。 有 m 个鸡蛋,用最坏的情况下实验次数最少的方法去找到k, 返回最坏情况下所需的实验次数。 样例 给出 m = 2 , n = 100 返回 14 给出 m = 2 , n = 36 返回 8 PO主宅心仁厚的把每一个步骤拆开了揉碎了给你们讲,具体细节我都在每一行的代码之上的注释里写的非常详尽。 在看下面的代码之前,PO主先结合扔鸡蛋这个例子讲下动态规划中的几个概念: 状态转移矩阵 :结合下面的例子,直观上看就是一个简单的二维数组,也可以把它叫做“备忘录”,这个备忘录存了上面这个问题的所有子问题的子答案!别小看了这个备忘录,它避免了大量的重复计算。不信,你用2个递归+1个循环实现试试,有2个鸡蛋的情况下,楼层到36就已经慢得快计算不出来结果了! 动态规划优势就体现在这儿了!当有很多重复子问题的时候,动态规划就是法拉利,其他暴力枚举递归等等都是QQ大众! 状态 :就是备忘录里存的一个个子问题答案,可以简单把理解为:状态=答案 状态转移方程 :就是写出母问题和子问题之间的关系!比如扔鸡蛋这个问题,你扔碎了,就转化成了往楼上找的子问题;你扔了没碎,那就转化成了往楼下找的子问题。 接下来就是通过一行行代码,配合每行代码上的注释来学习解动态规划的步骤!上车~ 利用 动态规划

装箱问题---动态规划

人走茶凉 提交于 2019-12-08 11:32:29
问题描述   有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。   要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。 输入格式   第一行为一个整数,表示箱子容量;   第二行为一个整数,表示有n个物品;   接下来n行,每行一个整数表示这n个物品的各自体积。 输出格式   一个整数,表示箱子剩余空间。 样例输入 24 6 8 3 12 7 9 7 样例输出 0 这题读完之后多思考思考, 其实就能发现就是0-1背包问题 每个物品的体积就是花费同时也是价值, 也就是说这题可以转化为在总体积为w下,可以得到最大的价值 最后用总体积减去最大的价值就是剩下最少的空间 状态转移方程d[j] = max(d[j], d[j - a[i]] + a[i]); #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int n; int d[20005]; int a[35]; int main(){ int w; scanf("%d%d", &w, &n); int i, j; for (i = 0; i < n; i++){ scanf("%d", &a[i]); } memset(d, 0, sizeof

动态规划—0-1背包问题(最易理解的讲解)

断了今生、忘了曾经 提交于 2019-12-08 11:29:59
0 -1 背包问题是最广为人知的动态规划问题之一,拥有很多变形。尽管在理解之后并不难写出程序,但初学者往往需要较多的时间才能掌握它。小编写这篇文章力争做到用通俗易懂的语言,最少的公式把 0-1 背包问题讲解透彻。 喜欢的小朋友,请与我多多交流哦 ~~~~ 请允许我从一则故事说起………… 话说 Lucy 带着她的亲友团去沙漠寻求宝藏,经过几天几夜的长途跋涉,终于在沙漠的那一边发现了一堆个大无比、闪闪发光的钻石,一共有 n 个。可惜的是他们身上只有一个能装钻石的背包,背包的容量为 W 。 Lucy 兴奋之余,在一堆钻石中挑出突出的钻石编号排列: 0,1,2,3 ……, n-1 。第 i 个宝石对应的体积和价值分别为 w[i] 和 v[i] 。排好后 Lucy 开始思考,和向他的亲友团求助:背包总共只能装下体积为 W 的东西,那我要装下哪些钻石才能使我们获得最大的利益呢? “很简单,用动态规划呀,那样我们就能获得最大的利益了” Bill 斩钉截铁的回答,他边说着边用木棍在沙漠上笔画着。 PS : 以上故事情节纯属虚构,若有模仿者,小编概不负责哦!请读者细细听下文讲解。 说时迟那时快, Bill 将挑出的 5 个钻石编号钻石,假设背包的容量范围在 [0,17] ,问题示例 物品的价值和重量如下表 现在 Bill 考考读者 , 通过可放和不可放表,是不是就能罗列出在背包容量值固定

【动态规划】01背包问题

♀尐吖头ヾ 提交于 2019-12-08 11:26:30
01背包问题 问题描述 给定 N 种物品和一个最大载重量为 C 的背包,物品 i 的重量是 wi,其价值为 vi 。 问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大? 问题分析 对于每个物品,只能选择装或者不装,不能选择只装物体的一部分,因此不能使用单位重量的价值进行排序的方法(贪心)来解决,需要用到动态规划来解决。 动态规划的三个核心 最优子结构 边界 状态转移方程 对于该问题而言,由于第i+1件物品只有两种选择(选与不选),因此前i+1件产品的最优解就是 前 ,子结构就是 前i件物品装在承重为j的容器中 ,可以用 result[i][j] 来表示。 边界就是在只装第一件物品时的情况。 通过上面的对子结构的分析,可以得到状态转移方程: 1. j < w[i]时,即剩余载重量不足以装下当前物品,应有最优解即是前i-1件时的解, result[i][j] = result[i-1][j] 2. j >= w[i]时,即还可以装下当前物品,因此解应为 装与不装 当前物品两种情况中的最大解。如果不装,即 result[i-1][j] ;如果装,,即 result[i-1][j-w[i]] + v[i] 。因此取最大值结果为 result[i][j] = max( result[i-1][j], result[i-1][j-w[i]] + v[i] ) 。 代码 1

动态规划之完全背包问题(java实现)

雨燕双飞 提交于 2019-12-08 11:26:17
之前写了01背包问题,现在写完全背包问题。和01背包不同的是,完全背包不限定某种物品的件数,可以装0,1,2,...,而01背包只有装与不装的区别。但是思考问题的方式还是一样的,我就其中的最大值。详细代码和注释见下面代码。 package backpack; /* f[i][v]:前i件物品放入背包容量为v的背包获得的最大收益 f[i][v] = max(f[i - 1][v],f[i - 1][v - k * Wi] + k * Vi,其中 1<=k<= v/Wi) 边界条件 f[0][v] = 0; f[i][0] = 0; */ public class CompleteBackpack { private static final int N = 3; private static final int V = 5; private int weight[] = {0,3,2,2}; private int Value[] = {0,5,10,20}; private int f[][]=new int[N+1][V+1]; public int Completeknapsack() { //边界条件,第0行和第0列的值设为0 for (int i = 0;i <= N;i++){ f[i][0] = 0; } for (int v = 0;v <= V;v++){ f[0]

最小邮票数(动态规划)

只谈情不闲聊 提交于 2019-12-07 12:22:58
题目描述 有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。 输入描述: 有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。 输出描述: 对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。 示例1 输入 10 5 1 3 3 3 4 输出 3 思路:01背包问题。 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<algorithm> using namespace std; #define INF 0x3f3f3f3f int dp[1001],stu[1001]; int min(int a,int b) { return a<b?a:b; } int main() { int i,j,n,m; int num=0; while(~scanf("%d",&m)) { scanf("