您的位置:首页 > 编程语言 > C语言/C++

暴力递归和动态规划解决二维数组最小路径和的问题(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/80275588https://blog.csdn.net/u014303647/article/details/80335627https://blog.csdn.net/weixin_37766296/article/details/80113760

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐