动态规划
- A : "1+1+1+1+1+1+1+1 =?"
- A : "上面等式的值是多少"
- B : 计算 "8"
- A : 在上面等式的左边写上 "1+" 呢?
- A : "此时等式的值为多少"
- B : 很快得出答案 "9"
- A : "你怎么这么快就知道答案了"
- A : "只要在8的基础上加1就行了"
- A : "所以你不用重新计算,因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'"
问题举例:70. 爬楼梯
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
输入:n = 3 输出:3 解释:有三种方法可以爬到楼顶。 1. 1 阶 + 1 阶 + 1 阶 2. 1 阶 + 2 阶 3. 2 阶 + 1 阶
方法1:带备忘录的递归解法
方法2:自底向上的动态规划
动态规划典型特征:最优子结构、状态转移方程、边界、重叠字问题
- f(n-1)和f(n-2) 称为 f(n) 的最优子结构
- f(n)= f(n-1)+f(n-2)就称为状态转移方程
- f(1) = 1, f(2) = 2 就是边界啦
- 比如f(10)= f(9)+f(8),f(9) = f(8) + f(7) ,f(8)就是重叠子问题。
什么样的问题适合用动态规划?
如果一个问题,可以把所有可能的答案穷举出来,并且穷举出来后,发现存在重叠子问题,就可以考虑使用动态规划。
一道动态规划问题,其实就是一个递推问题。假设当前决策结果是f(n),则最优子结构就是要让 f(n-k) 最优,最优子结构性质就是能让转移到n的状态是最优的,并且与后面的决策没有关系,即让后面的决策安心地使用前面的局部最优解的一种性质。
问题举例:现有一个整数数组 nums ,找到其中最长严格递增子序列的长度。
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
高数Umaru系列(9)——哈士奇
Description
由于高数巨养的喵星人太傲娇了,要天天吃新鲜猫粮而且还经常欺负高数巨,所以高数巨决定买几条哈士奇尝尝鲜。这天高数巨来到了二手狗市场买哈士奇,高数巨看完了所有的哈士奇,记下了每条哈士奇的价格,并根据对它们的好感程度给它们每只都赋予了一个萌值。高数现在手里有X元,她想通过购买若干条哈士奇来获得尽可能多的萌值。现在给定高数巨手里的钱X以及N条哈士奇的价格和萌值,求高数巨最多可获得多少萌值
Input
多组输入。
对于每组输入,第一行有两个整数N,X(1 < = N < = 100,1 < = X < = 1000),分别表示哈士奇的数量和高数巨的钱数
接下来的N行每行有两个整数Pi,Mi(1 < = Pi,Mi < = 100),分别表示第i条哈士奇的价格和萌值
Output
对于每组数据,输出一个整数,表示高数巨最多可以获得的萌值,每组输出占一行
Samples
Sample #1
Input
Output
2 100 50 20 60 40 3 100 20 55 20 35 90 95 1 10 20 50
40 95 0
1 #include<stdio.h> 2 #include<string.h> 3 4 int max(int x, int y) 5 { 6 if(x>y) return x; 7 else return y; 8 } 9 10 int main() 11 { 12 int p[105], m[105], a[105][1005], n, x, i, j; 13 while(~scanf("%d %d", &n, &x)) 14 { 15 for(i=1;i<=n;i++) // 从1开始,因为0是边界也是值!因为这里Wa了10+次 16 { 17 scanf("%d %d", &p[i], &m[i]); 18 } 19 memset(a, 0, sizeof(a)); // 每次都需要初始化 20 21 for(i=1;i<=n;i++) // 第几个哈士奇 22 { 23 for(j=1;j<=x;j++) // 价钱 24 { 25 if(p[i] <= j) // 买得起,可以买,也可以不买 26 a[i][j] = max(a[i-1][j], a[i-1][j-p[i]] + m[i]); 27 else a[i][j] = a[i-1][j]; // 买不起,就不买 28 } 29 } 30 printf("%d\n", a[n][x]); 31 } 32 return 0; 33 }