暴力递归和动态规划解决二维数组最小路径和的问题(C++实现)
2019-03-24 21:21
1296 查看
暴力递归:
1, 把问题转化为规模缩小了的同类问题的子问题
2, 有明确的不需要继续进行递归的条件(base case)
3, 有当得到了子问题的结果之后的决策过程
4, 不记录每一个子问题的解
动态规划:
1, 从暴力递归中来
2, 将每一个子问题的解记录下来, 避免重复计算
3, 把暴力递归的过程, 抽象成了状态表达
4, 并且存在化简状态表达, 使其更加简洁的可能
[code]#include<iostream> #include<vector> using namespace std; class Solution { public: int minPathSum(vector<vector<int> > &grid,int i,int j) {//暴力递归实现,参数i,j表示从点(i,j)到右下角点的最短路径 if (grid.empty()) return 0; int m = grid.size(); int n = grid[0].size(); if (i == m - 1 && j == n - 1)//点(i,j)如果就是右下角点,那么直接返回 return grid[i][j]; if (i == m - 1) return grid[i][j] + minPathSum2(grid, i, j + 1);//最后一行是basecase if(j==n-1) return grid[i][j]+ minPathSum2(grid, i+1, j);//最后一列也是basecase int right= minPathSum2(grid, i, j + 1); int down = minPathSum2(grid, i + 1, j); return (right < down ? right : down) + grid[i][j]; //从(i,j)点到右下角点的最短路径等于(i,j)点的值和(i+1,j)点、(i,j+1)点到右下角点最短路径较小的相加 } int minPathSum(vector<vector<int> > &grid) {//动态规划实现 if (grid.empty()) return 0; int m = grid.size(); int n = grid[0].size(); vector<vector<int>> dp(m, vector<int>(n, grid[0][0])); for (int i = 1; i<m; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0];//第一列的值是可以确定的,是basecase } for (int i = 1; i<n; i++) { dp[0][i] = dp[0][i - 1] + grid[0][i];//第一行的值也是可以确定的,是basecase } for (int i = 1; i<m; i++) { for (int j = 1; j<n; j++) { dp[i][j] = (dp[i - 1][j]<dp[i][j - 1]? dp[i - 1][j]: dp[i][j - 1]) + grid[i][j]; //到(i,j)点的最短路径等于到(i-1,j)点和到(i,j-1)点的最短路径短的那个再加上(i,j)点的值 } } return dp[m - 1][n - 1]; } }; int main() { vector<vector<int>> v(4, vector<int>(3));//这块是4行3列二维vector的初始化,用二维vector比二维数组要简单些 for (int i = 0; i<4; i++) for (int j = 0; j<3; j++) v[i][j] = i+j; Solution s; cout << s.minPathSum(v) << endl; cout << s.minPathSum2(v,0,0) << endl; system("pause"); return 0; }
从上面图片可以看出,暴力递归会重复计算,浪费时间,而动态规划使用了一个二维数组dp来保存已经求出来的那些点最短路径,动态规划算法是 “记住求过的解来节省时间”,用空间换时间,它的核心就是记住已经解决过的子问题的解。
然后对于为什么使用二维数组保存已经求出的解,为什么不是一维呢?我们分析可变参数,可变参数是二维vector的横纵坐标i和j,可变参数有几个就用几维的表来存,二维vector的长宽的范围就是两个可变参数的范围,每个位置表示(0,0)到此位置的最短路径,所有的返回值一定可以装在这张二维表里面,把二维表的basecase填好(也就是第一行和第一列 ),二维表(m-1,n-1)的位置就是我要求的结果,看其中求普通位置需要哪些其他位置的值,逆着回去就是我填表的顺序。
参考:https://blog.csdn.net/weixin_38628152/article/details/80275588和https://blog.csdn.net/u014303647/article/details/80335627和https://blog.csdn.net/weixin_37766296/article/details/80113760
相关文章推荐
- 动态规划(三)暴力递归的优化之路——数字矩阵的最小路径和
- 3行核心代码解决汉诺塔问题(C++递归实现)
- 算法初级面试题08——递归和动态规划的精髓、阶乘、汉诺塔、子序列和全排列、母牛问题、逆序栈、最小的路径和、数组累加成指定整数、背包问题
- 最短路径问题——Dijkstra算法(C++实现)
- ACM最长公共子序列问题(动态规划)C++实现
- MFC使用CEF并实现js与C++交互功能,解决Render进程中OnContextCreated绑定与OnWebKitInitialized的js扩展无法回调问题
- XSLT实现XML无极限树(精简版)[二] 解决没有递归出节点属性值总和的问题(JS实现)
- 0-1背包问题与完全背包问题C++实现 动态规划
- C++递归解决斐波那契数列问题
- 0/1背包问题 - 动态规划(C++实现)
- 矩阵链乘法问题(给A1A2A3...An加括号,使之乘法次数最小)动态规划问题C++实现
- CKEditor使用js结合CKFinder实现上传,解决项目路径问题
- 遗传算法 解决TSP问题 C++实现(一)
- 【高级算法】遗传算法解决3SAT问题(C++实现)
- 模拟退火算法求函数最小值问题的C/C++实现
- 动态规划解决01背包问题(java实现)
- 狄克斯特拉算法,解决加权最短路径问题--python实现
- 经典算法<一>迷宫问题 1.单条路径 DFS求解 C++实现
- 实现ServletContextListener解决项目资源访问路径不统一的问题
- C++关于CFileDialog的更改路径问题及解决方法