动态规划用法总结(一)
动态规划是一个相对高级的工具,有些本身是动态规划的题可以用动态规划以外,当你无法一眼看穿最优解法时,你可以考虑直接使用动态规划。
动态规划最常见的解法思路步骤是
- 设计状态
- 设计转移方程
- 对转移方程时间空间优化
- 大多数可以改写为递推
- 边界处理
- 实现
优点是,基于状态和状态转移,空间复杂度时间复杂度在完全思考前容易预估计,状态一般与输入参数大小直接相关,容易设计,常见的贪心类的,堆栈类的有不少可以用动态规划实现。同时当实现完后,在优化过程中,可能可以推出最优解法。
当然伴随的缺点也是,可能比最优解法在时空复杂度会相对更高
技巧
- 一维状态转移
state[i] = f(state[i-1]);
- 一维状态多值转移
state[i] = f(state[i-1],...,state[i-k]);
- 一维状态常系数线性转移方程 改写为 矩阵乘法
state[i] = a1*state[i-1] + a2*state[i-2] ... + ak*state[i-k]);
- 多个一维状态转移
stateA[i] = f(stateA[i-1],...,stateA[i-j],stateB[i-1],...,stateB[i-k]);
stateB[i] = g(stateA[i-1],...,stateA[i-m],stateB[i-1],...,stateB[i-n]);
- 多维度状态转移
state[i][j] = f(state[i-1][j-1],state[i-1][j],state[i][j-1],...);
- 多维度一维转换
state[i*MAXJ+j] = stateold[i][j];
练手题目
题目1
这道题可以用技巧1, 一维状态来记录从数组起始到上一个的最小值,
state[i] = min(val[i], state[i-1]);
题目2
这道题可以用技巧5, 设置多维状态转移
state[i][j] = state[i-1][j] + state[i][j-1]
题目3
这道题可以用技巧5, 设置多维状态转移, 相对于上面的求路径,转移方程更复杂
if(p[i] == '*')
state[i][j] = state[i-1][j] | state[i][j-1] | state[i-1][j-1];
if(p[i] == '?' || p[i] == s[j])
state[i][j] = state[i-1][j-1];
题目4
这道题可以使用技巧2,通过分析上一个合法序列和当前构成的关系,转移方程也比题目1更复杂
if(s[i] == '(') continue;
state[i] = s[i-1-state[i-1]] == '(' ? state[i-1] + 2 + state[i-2-state[i-1]]: 0
题目5
这道题可以使用技巧1, 记录之前的值的前缀和的最小值
state[i] = min(state[i-1], presum[i])