矩阵的最小路径和 [DP]
来源:互联网 发布:软件测试原佩腾 编辑:程序博客网 时间:2024/03/29 07:34
从本文开始,我打算多刷一些动态规划的题。不仅如此,各种典型算法也会在分类刷一刷。
【题目】
给定一个矩阵,从左上角开始每次只能向右或者右下走,最后到达右下角的位置,路径上所有数字累加起来就是路径和,返回所有路径中最小的路径和。
【举例】
如果给定的m如下:
1,3,5,9
8,1,3,4
5,0,6,1
8,8,4,0
路径1,3,1,0,6,1,0是所有路径中路径和最小的,所以返回12。
【解答】
这道题是很明显的动态规划算法,动态规划算法的一般步骤就是列一张表来存放计算过的值,通常采用数组实现。这道题的特殊之处在于表的值不仅和自身有关,而且和原矩阵也是相关的。表中的值需要和原矩阵中的值相加,因为我们求的是路径和。
矩阵如下,只画了一部分,动态规划通常会申请+1的空间,i=0和j=0用来存放动态规划的初始值,这里我们赋为0,这张表是B[m+1][n+1]。
:0 1 2 3 4
0: 0 0 0 0 0
1: 01 4 9 18
2: 0 9 5
...
不难看出,B[1][j]和B[i][1]是取它上下两个相邻值再加上原数组A[i-1][j-1]的值(看1和4),为什么减一是因为规划表真实数据从1开始而不是从0开始。这些其实是为了初始化下标为1的这些点。
除了下标为i=1或j=1的部分,其他值(看5)是上下相邻两个值得最小值与原数组A[i-1][j-1]的值相加。这就是dp数组的公式了。
我第一种解法就没有初始化,直接放在循环里面做了,不过效率肯定不高,下面是我第一种解法,可以和第二种对比一下。
for(int i=1; i<=m; ++i){ for(int j=1; j<=n; ++j){ if(i == 1 || j == 1) B[i][j] = std::max(B[i-1][j], B[i][j-1]) + A[i-1][j-1]; else B[i][j] = std::min(B[i-1][j], B[i][j-1]) + A[i-1][j-1]; } }
其实最早的第一次解我都没有考虑到下标为1的应该是max,当时我直接只用了一个min,然后求得结果为11,还好我认识到了错误。
起始也不用std::max,直接相加就行了
下面看第二种完整代码,注意第二种只是参考,还有第三种,我没有删除这个是为了警示我自己考虑要周全,突然又想到的。
int min_path(const std::vector<std::vector<int>>& A){ if(A.size() == 0) return 0; int m = (int)A.size(); int n = (int)A[0].size(); std::vector<std::vector<int>> B(m+1, std::vector<int>(n+1, 0)); for(int i=1; i<=m; ++i) B[i][1] = B[i-1][1] + A[i-1][0]; for(int j=1; j<=n; ++j) B[1][j] = B[1][j-1] + A[0][j-1]; for(int i=2; i<=m; ++i){ for(int j=2; j<=n; ++j){ B[i][j] = std::min(B[i-1][j], B[i][j-1]) + A[i-1][j-1]; } } return B[m][n];}
第三种:分配同样的大小就可以了,不需要i-1和j-1了。
int min_path(const std::vector<std::vector<int>>& A){ if(A.size() == 0) return 0; int m = (int)A.size(); int n = (int)A[0].size(); std::vector<std::vector<int>> B(m, std::vector<int>(n, 0)); B[0][0] = 1; for(int i=1; i<m; ++i) B[i][0] = B[i-1][0] + A[i][0]; for(int j=1; j<n; ++j) B[0][j] = B[0][j-1] + A[0][j]; for(int i=1; i<m; ++i){ for(int j=1; j<n; ++j){ B[i][j] = std::min(B[i-1][j], B[i][j-1]) + A[i][j]; } } return B[m-1][n-1];}第三种直接分配相同大小的空间就可以了。唉,动态规划分配空间就是要么加1,要么不加1,我还是不够熟练。
测试用例:
int main(){ std::vector<std::vector<int>> A = { {1, 3, 5, 9}, {8, 1, 3, 4}, {5, 0, 6, 1}, {8, 8, 4, 0}}; int find = min_path(A); std::cout<<"the min path is : "<<find<<std::endl; typedef std::vector<std::vector<int>>::iterator iterator1; typedef std::vector<int>::iterator iterator2; for(iterator1 iter= A.begin(); iter!=A.end(); ++iter){ for(iterator2 it = (*iter).begin(); it!=(*iter).end(); ++it) std::cout<<*it<<' '; std::cout<<std::endl; } return 0;}
继续刷题中。。。
- 矩阵的最小路径和 [DP]
- 矩阵的最小路径和
- 矩阵的最小路径和
- 矩阵的最小路径和
- 矩阵的最小路径和
- 矩阵的最小路径和
- 矩阵的最小路径和
- 矩阵最小路径和
- 矩阵最小路径和
- 动态规划--矩阵最小的路径和
- 矩阵最小路径和练习
- 矩阵的最小路径之和
- 矩阵的最小路径和(空间压缩)
- 递归与动态规划---矩阵的最小路径和
- 动态规划之矩阵的最小路径和
- 动态规划,矩阵最小路径和
- 矩阵最小路径和(java实现)
- 动态规划--矩阵最小路径和
- TransitionDrawable的使用
- promise 特点总结
- java运算符记录
- 如何从Eclipse 迁移到Android Studio 且保持Eclipse项目结构
- React常用插件介绍:React中我们为什么要用 redux-thunk,它能做什么?
- 矩阵的最小路径和 [DP]
- Android高效率编码-细节,控件,架包,功能,工具,开源汇总
- Java编译器的行为------第一节:方法
- Activity和Fragment的数据传递
- U1077:error C:\Windows\System32\cscript.exe return code 1 wince7编译很变态的问题
- mybatis 最简单的执行自定义SQL语句
- 如何使用Git上传项目代码到github
- 从零开始学网络爬虫之数据区MySQL
- Log4j2配置之Appenders