转载至https://blog.csdn.net/weixin_38278878/article/details/80037455
学习动态规划,愚认为,就是解决以下的三个问题:
什么是动态规划?什么时候要用动态规划?怎么使用动态规划?
让我们一个一个来解决!
1、什么是动态规划?
动态规划是求解决策过程最优化的数学方法。把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
2、什么时候要用动态规划?
动态规划的特点
- 求最优解
- 整体问题的最优解依赖各子问题的最优解
- 子问题之间还有相互重叠的更小的子问题
3、怎么使用动态规划?
- 判题题意是否为找出一个问题的最优解
- 从上往下分析问题,大问题可以分解为子问题,子问题中还有更小的子问题
- 从下往上分析问题 ,找出这些问题之间的关联(状态转移方程)
- 讨论底层的边界问题
- 解决问题(通常使用数组进行迭代求出最优解)
纸上得来终觉浅,绝知此事要躬行。举几个例子:
例子1:
剑指Offer(第二版)面试题14:剪绳子
给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],…,k[m].请问k[0]k[1]…*k[m]可能的最大乘积是多少?
例如,当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18.
看完题目,我们按照上面提到的“动态规划五部”解决问题
1、判题题意是否为找出一个问题的最优解
看到字眼是“可能的最大乘积是多少”,判断是求最优解问题,可以用动态规划解决;
2、从上往下分析问题,大问题可以分解为子问题,子问题中还有更小的子问题
题目中举了个例子:当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18;我们可以从这里开始突破,把长度为8绳子的最大乘积分解为数个子问题,长度为8我们可以把它看成长度为1和7的绳子的和,或者长度 为2和6的绳子的和,或者长度为3和5的绳子的和and so on!
到这里,相信大家已经看到一丝真理了吧?
3. 从下往上分析问题 ,找出这些问题之间的关联(状态转移方程)
在第二点时,我们已经从上到下分析问题了,现在我们要从下往上分析问题了。分析可知,
f(8) 的值就是f(1)*f(7),f(2)*f(6),f(3)*f(5),f(4)*f(4)它们之中的最小值,即f(8) = Max{f(1)*f(7),f(2)*f(6),f(3)*f(5),f(4)*f(4)}
只要知道f(1)到f(7)的值就能求出f(8);对于f(7),只要知道f(1)到f(6)的值就能求出f(6);对于f(6),只要知道f(1)到f(5)的值就能求出f(6);以些类推,我们只要知道前几个边界的值,就能一步步迭代出后续的结果!
*状态转移方程: f(n)=Max{f(n-i)f(i)} i={1,2,3,…,n/2}
4. 讨论底层的边界问题
底层的边界问题说的就是最小的前几个数值的f(n)的值,本题中就是f(0)、f(1)、f(2)、f(3)的值
对于f(0),长度为0的绳子,没办法剪,没有意义
对于f(1),长度为1的绳子,没办法剪,设为1
对于f(2),长度为2的绳子,只有一种剪法,剪成两段长度为1的绳子,但剪后的乘积为1,比自身更小;如果不是求自身的值,要求乘积最大值的话就没必要剪。
对于f(3),长度为3的绳子,只有一种剪法,剪成两段长度为1和2的绳子,但剪后的乘积为2,比自身更小;如果不是求自身的值,要求乘积最大值的话也没必要剪。
对于f(4), 自身值和剪后各段乘积的值相等都是4
对于f(5), 剪后各段乘积的值为6,大于自身值,故只需要列出f(1) - f(3)的值即可,相当于是特例
5、解决问题
这一部就是写代码了
class Solution {
public:
int cutRope(int number)
{
if(number <= 1)
return 0;
if(number == 2)
return 1;
if(number == 3)
return 2;
int arr[number+1];//f(i) = arr[i]
arr[0] = 0;
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
int max = 0;
for(int i=4; i<=number; i++)
{
for(int j=1; j<=i/2; j++)
{
arr[i] = arr[j]*arr[i-j];
if(arr[i] > max)
max = arr[i];
}
arr[i] = max;
}
return arr[number];
}
};
例子2:
跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级台阶总共有多少种跳法。
1、判题题意是否为找出一个问题的最优解
这个我还真的看不出,直觉判断这题可以通过动态规划迭代出来….有经验的网友可以分享下看法,指导一下本小白白。
2、从上往下分析问题,大问题可以分解为子问题,子问题中还有更小的子问题
题目中没有给粟子,我们可以自己举点粟子。例如,跳上一个6级台阶台阶,有多少种跳法;由于青蛙一次可以跳两阶,也可以跳一阶,所以我们可以分成两个情况
1、青蛙最后一次跳了两阶,问题变成了“跳上一个4级台阶台阶,有多少种跳法”
2、青蛙最后一次跳了一阶,问题变成了“跳上一个5级台阶台阶,有多少种跳法”
由上可得f(6) = f(5) + f(4);
由此类推,f(4)=f(3) +f(2)
3.、从下往上分析问题 ,找出这些问题之间的关联(状态转移方程)
跟上面的例题一相同,可以由f(1)逐渐迭代上去
由2可得,状态转移方程为:f(n)=f(n-1)+f(n-2)
4、边界情况分析
跳一阶时,只有一种跳法,所以f(1)=1
跳两阶时,有两种跳法,直接跳2阶,两次每次跳1阶,所以f(2)=2
跳两阶以上可以分解成上面的情况
5、解决问题
class Solution {
public:
int jumpFloor(int number)
{
int res;
int index;
int resk_1 = 2;
int resk_2 = 1;
if(number>2)
{
for(index = 3; index <= number; index++)
{
res = resk_1 + resk_2;
resk_2 = resk_1;
resk_1 = res;
}
return res;
}
else
{
return number;
}
}
};
————————————————
版权声明:本文为CSDN博主「食鱼酱」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38278878/article/details/80037455