动态规划

[POJ1664]放苹果(动态规划)

╄→гoц情女王★ 提交于 2020-03-26 18:34:02
[POJ1664]放苹果 Description 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。 Input 第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。 Output 对输入的每组数据M和N,用一行输出相应的K。 Sample Input 1 7 3 Sample Output 8 考虑dp dp[i][j]表示前i个苹果放入前j个盘子中的方案数 因为可以有盘子不放苹果 当i<j时,dp[i][j]=dp[i][i] (盘子和苹果均为相同的) 当i>=j时,此时可能盘子上都有苹果,我们把每个盘子上都拿走一个苹果,方案数不会变。(很妙啊) \[dp[i][j]=dp[i-j][j] \] 也可能盘子上没有苹果 \[dp[i][j]=dp[i][j-1] \] #include<bits/stdc++.h> using namespace std; int n,m,dp[15][15]; void work(){ cin>>n>>m; for(int i=0;i<=m;i++)dp[0][i]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(i<j)dp[i][j]

最大连续子数组,动态规划基础

孤街浪徒 提交于 2020-03-26 12:01:59
动规思想: 状态转移方程:temp[i] = (temp[i-1]>0?temp[i-1]:0)+a[i]; temp[i]表示以第i个数字 结尾 的子数组的最大和 分析题目可知:temp[i]由两种情况: 1.当以第(i-1)个数字为结尾的子数组中最大和temp(i-1)小于0时,如果把这个负数和第i个数相加,得到的结果反而比第i个数本身还要小,所以这种情况下(以第i个数字为结尾的子数组)最大子数组和是第i个数本身。 2.如果以第(i-1)个数字为结尾的子数组中最大和temp(i-1)大于0,与第i个数累加就得到了以第i个数结尾的子数组中最大和。 于是我们只需求出temp数组中最大的那个数便是最大子数组的和! (可以看出这个状态转移方程并非直接得出最大连续子数组和,而是得出以 第i个数字结尾的子数组的最大和 ,因为要得到最大连续子数组和,必须先得到temp[i]( i从0到n,就依次得出了子数组的各种可能 ),于是temp存的便是以i结尾的最大子数组和,挑出最大的便是整个数组的最大子数组和) 上代码: #include<iostream> using namespace std; int getMax(int *arr,int n,int start,int end){ int max; int firstmax = arr[0]; max = arr[0]; for(int i

poj--1579--(DFS+记忆化搜索之经典)

末鹿安然 提交于 2020-03-26 07:20:50
记忆化搜索 记忆化搜索:算法上依然是搜索的流程,但是搜索到的一些解用 动态规划 的那种思想和模式作一些保存。 一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。 更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。 记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来, 以后再次遇到这个状态的时候,就不必重新求解了。 这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。 虽然不能使用传统意义上的动态规划解决本题,但动态规划的思想仍然能起到作用。搜索相对于动态规划最大的劣势无非就是重复计算子结构,所以我们在搜索的过程中,对于每一个子结构只计算一次,之后保存到数组里,以后要用到的时候直接调用就可以了,这就是我要介绍的记忆化搜索。 记忆化搜索的实质是动态规划,效率也和动态规划接近,形式是搜索,简单直观,代码也容易编写,不需要进行什么拓扑排序了。 可以归纳为:记忆化搜索=搜索的形式+动态规划的思想 如下例: #include<stdio.h> #include<stdlib.h> #include<string.h> //using namespace std; int arr[22][22][22]; int sum(int a,int b,int c){ if(a<=0||b<=0|

hdu 1078 记忆化搜索

北战南征 提交于 2020-03-26 07:16:40
题意:每一位置有特定量食物。耗子从(0,0)开始一次只能向左或右前进不多于k步且下一个位置的食物必须比当前位置多,问耗子所能吃到的食物的最大量。 1、此题目为搜索的题目,寻找能够满足条件的位置。 2、求最大食物量,不同位置有有限个选择(只能去食物更多的地方),分别选择出最优后,搜索过程中可求出(0,0)开始所能吃到的最大量。这里记录的就是从该位置开始吃,所能获得的最大食物量dp[i][j]. 百度百科中记忆化搜索的描述及例题 记忆化搜索:算法上依然是搜索的流程,但是搜索到的一些解用 动态规划 的那种思想和模式作一些保存。 一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。 更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。 记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来, 以后再次遇到这个状态的时候,就不必重新求解了。 这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。 可以归纳为:记忆化搜索=搜索的形式+动态规划的思想 正文写完了就开始吐一下槽,hdoj服务器有时候也不稳定,同样的代码也可能tle,如果实在找不到问题的时候可以换一个时间提交。嗯~ #include<stdio.h> #include<string.h> int map[105][105],dp[105]

动态规划算法题(5题)

北城以北 提交于 2020-03-24 23:53:20
1、题目描述(网易) 有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗? 输入描述: 每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数, 按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。 输出描述: 输出一行表示最大的乘积。 试题分析:本题要使用动态规划来解,动态规划的特点:1.求解的是最优化问题;2.可以分解为最优子结构本题可以先求解在第i个学生的位置下,j(j<K)个学生的能力值的最大值,得到所有学生位置下j个学生的能力值的最大值;在j个学生的情况下,得到j+1个学生的最大值,最后得到k个学生的最大值,下面以一个例子来解释(注意因为有负数,所以要计算最小值,同时保存):样例输出:     10     8 7 2 -7 9 5 4 10 -7 1     3 3输出:   630如上,第一步先计算k=2的情况:7:在d=3的情况下,最大最小值都为562:在d=3的情况下,最大值为16,最小值为14-7:在d=3的情况下

[知识点]动态规划基础

ぃ、小莉子 提交于 2020-03-20 16:30:51
一、前言 最近又做了一些比较基础的DP,感觉自己无敌了,应该有资格写篇文章来介绍了! 本文主要介绍动态规划的概念,记忆化搜索以及动态规划的核心。 二、介绍 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。其本质是将一个复杂的问题拆分成若干个相对简单的子问题,所以常适用于有重叠子问题和最优子结构问题。 这样介绍动态规划是很空洞而抽象的,我们从更简单的方式切入。 三、记忆化搜索?动规? 山洞里有 m 株不同的草药,第 i 株草药的价值为v[i],采第 i 株草药需要时间 t[i]。在时间 T 内,要求采集一些草药,使总价值最高。 不知道动规碰到这道题的唯一方法为 暴力搜索 ——进行DFS,对于每一株有选与不选两个选项,从第 1 株开始逐一进行二选一,如果出现时间超过限定则回溯;直到对 m 株都进行了选择,记录当前的价值并和最大价值比较,选择较大值,以此反复,可得最优解。核心代码如下: 1 void dfs(int o, int ot, int ov) { 2 if (ot > T) return; 3 if (o == m + 1) { 4 ans = max(ans, ov); 5 return; 6 } 7 dfs(o + 1, ot, ov); 8 dfs(o + 1, ot + t[o],

最长回文子序列-----动态规划

折月煮酒 提交于 2020-03-20 05:13:43
完全没思路啊没思路。。。。Copy代码,想书写一遍矩阵,还被卡住了,完全不知道自己错在哪里!! 解题思路: 动态规划。 设立一个len行len列的dp数组~dp[i][j]表示字符串i~j下标所构成的子串中最长回文子串的长度~最后我们需要返回的是dp[0][len-1]的值~ dp数组这样更新:首先i指针从尾到头遍历,j指针从i指针后面一个元素开始一直遍历到尾部~一开始dp[i][i]的值都为1,如 果当前i和j所指元素相等,说明能够加到i~j的回文子串的长度中,所以更新dp[i][j] = dp[i+1][j-1] + 2; 如果当前元素不相 等,那么说明这两个i、j所指元素对回文串无贡献,则dp[i][j]就是从dp[i+1][j]和dp[i][j-1]中选取较大的一个值即可。 class Solution{ public: int longestPalindromeSubseq(string s) { vector<vector< int>> dp(s.length(),vector< int>(s.length())); for( int i=s.length()-1;i>=0;i--) { dp[i][i]=1; for( int j=i+1;j<s.length();j++) { if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]+2; else

算法思想

醉酒当歌 提交于 2020-03-17 13:44:34
算法复杂性: 算法运行时所需要的计算机资源的量。 <1>时间复杂性,<2>空间复杂性 穷举法的基本思想: 对问题的所有可能状态一一测试,直到找到解或将全部可能状态都测试为止。 分治法的基本思想: 将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同;对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题的规模足够小,很容易求出其解为止;将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上求出原来问题的解。 二路归并排序算法的基本思想: 将待排序元素分成大小大致相同的两个子集,按照这种方法一直进行下去,直到每个子集中只有一个元素,然后自底向上逐步合并排序,最终合并成有序集合。 贪心法的基本思想: 在对问题求解时总是做出在当前来看是最好的选择,即不从整体最优加以考虑,仅是在某种意义上的局部最优。 贪心法求解问题具有的性质: <1>贪心选择性质:所求问题的整体最优解可以通过一系列局部最优解的选择来达到。 <2>最优子结构性质:一个问题的最优解包含其子问题的最优解。 贪心法求解问题的基本过程: <1>建立数学模型来描述问题 <2>把求解的问题分成若干个子问题。 <3>对每一个子问题进行求解,得到子问题的局部最优解。 <4>把子问题的局部最优解合成原问题的一个解。 动态规划的基本思想: 动态规划和分治法类似

动态规划求子序列和子串问题

倾然丶 夕夏残阳落幕 提交于 2020-03-17 06:39:25
LeetCode子序列问题: 300. 最长上升子序列 ; 673. 最长递增子序列的个数 ; 1143. 最长公共子序列 ; 516. 最长回文子序列 LeetCode子串问题: 5. 最长回文子串 ; 14. 最长公共前缀 300. 最长上升子序列 int max(int a,int b){ return a>b?a:b; } int lengthOfLIS(int* nums, int numsSize){ int i,j,rst=0; int dp[numsSize+1]; if(numsSize<=1)return numsSize; for(i=0;i<numsSize;i++){ dp[i]=1; for(j=0;j<i;j++){ if(nums[i]>nums[j]){ dp[i]=max(dp[i],dp[j]+1); } if(rst<dp[i])rst=dp[i]; } } return rst; } 673. 最长递增子序列的个数 int max(int a,int b){ return a>b?a:b; } int findNumberOfLIS(int* nums, int numsSize){ int i,j,dp[numsSize+1],maxnum=0,cnt[numsSize+1]; if(numsSize<=1)return numsSize

继续探索-最长上升子序列--贪心+二分+动态规划(综合运用)

空扰寡人 提交于 2020-03-17 06:25:29
0x01.问题 具体问题可参考上篇博客,本文主要讲述另一种思路: 最长上升子序列--从数学归纳到动态规划 0x02.(贪心+二分+动态规划)思路体现 在上篇博客中,主要是运用动态规划的思路去解决这个问题,时间复杂度为O(n^2) 现在,我们来考虑如何使用更加巧妙的二分法来解决(含贪心和动态规划的思路) 贪心的思路体现: 所谓贪心就是贪,追求每一步都能找到最合适的解,然而在大多数情况下,这是不现实的,所有我们就要退而求其次,找到尽可能好的解。我们首先考虑一下简单的 贪心,如果要使得上升的子序列尽可能长,要满足什么条件? 一个子序列是不断上升的, 要它尽可能的长一点,那么最好的办法就是让它升的慢一点,升的越慢,它就可能越长。 也就是说, 如果已经得到的上升子序列的结尾的数越小,遍历的时候后面接上一个数,就会有更大的可能性构成一个更长的上升子序列。 针对贪心的思路去改变动态规划: 我们为了达到这个贪心的思想,我们需要改变动态规划的相应构造。 第一个就是 状态 : 既然结尾越小越好,我们可以记录 在长度固定的情况下,结尾最小的那个元素的数值。 定义状态: tail[i] 表示长度为 i+1 的所有上升子序列的结尾的最小值。 例如:对于序列[10,9,2,5,3,7,56],tails[0]=2,tails[1]=3,tails[2]=5,tails[3]=7,tails[4]=56