动态规划入门—例题理解
目录
动态规划(dynamic programming)
前提:递归,暴力搜索
通过例题理解动态规划…
例题:抢劫街道
小偷抢劫一条街道的各家,要求不能抢劫相邻两家,否则触发警报,问如何抢劫可以得到最多钱财。
先暴力方法(暴力方法是解决一切问题的方法)-----------à一定是递归 Public int solve(int idx,int[] nums);//输入抢到第几家,与各家的钱数;输出抢到的钱数
不抢-----------获得下一家的钱数
Math.max(nums[idx]+slove(idx-2,nums), solve(idx-1,nums)) 全局最优化 |
从n开始,是一种习惯
时间复杂度:太高
重叠子问题:
去冗余----------------------空间换时间
Idx从n-1开始--à(n-3, n-4, n-5…….)
Idx从n-2开始--à(n-4, n-5……..)
如何优化算法--à减少重复计算
If(idx 算过)
直接返回结果;
解决方法:开一个数组存已经算过的索引idx的抢到的钱数 result[]
初始化数组全为-1.
If(result[idx]>=0)
Return result[idx];
其中,数组后面的赋值result[idx] = Math.max(nums[idx]+slove(idx-2,nums), solve(idx-1,nums));
后效性
贪心-----------------贪心天生没有后效性
归属于动态规划的题型:
套路:最大 最小 最优 最长 计数
离散问题:背包问题
最优子结构:N-1可以推导出N
基本步骤
- 设计暴力算法,找到冗余
- 设计并存储状态(一维 二维 三维数组 map)
- 递归(函数 自调用)/递推(公式 for循环)
- 自底向上(n开始)/自顶向下(0开始 需要考虑前几个idx的值取值) 计算最优解
递归实例:
斐波那契数列:F(n) = F(n-1) + F(n-2);
N!: F(n) = F(n-1) *n;
例题:小兵向前冲
N*M的棋盘 小兵从左下角->右上角 只能向上向右 问有多少种走法
套路:计数问题
解题思路:暴力搜索(回溯法 递归 搜索)
输入(n, m)
决策:
???原问题与子问题的关系
F(n, m):在n*m棋盘上已经到达右上角时的走法有多少种--------它是有哪些子问题可以推导出来呢?
(n-1, m)向右走+ (n, m-1)向上走
所以: F(n, m) = F(n-1, m) + F(n, m-1);
考虑边界条件:if(n==0 || m==0) return 0;
If(n==1 || m==1) return 1;
拓展:
组合数递推公式C(n,r)----------------- 区分-通项公式
边界条件: if(r==0)
If(n<r)
决策:nCr(n, r) = nCr(n-1, r-1) + nCr(n-1, r);-----------------类似小兵走斜线(斜上)与向上
全排列递推公式
添加限制条件:
小兵在棋盘上的某格不能走---------------在那一个添加的走法种类为0
小兵可以在一个方向上走一步或两步F(n, m) = F(n-1, m) + F(n, m-1)
+F(n-2, m) + F(n, m-2)
小兵可以在一个方向上走k步
F(n, m, k)
上楼梯问题:
一步可以跨一级或两级,要上到n级,有多少种走法
F[n] = F[n-1] + F[n-2]
F[n] = F[n-1] + F[n-2] + F[n-3] +…+ F[n-k]
寻路算法
单元最短路
双元最短路
其他:
八皇后问题
练题网址~Littlecode??