编程-从矩阵左上角走到右下角
来源:互联网 发布:mac英国官网 编辑:程序博客网 时间:2024/05/16 15:28
题目要求:
编写一个算法,在非负矩阵中,从左上角走到右下角,每次只能向左或向下移动一格,输出走过的路径节点坐标和最小权值。
方法:动态规划法
状态转移方程stat[i][j] = min{stat[i-1][j], stat[i][j-1]}。
逻辑:目的节点是从其上边节点或左边节点下来的,判断上边节点和左边节点哪个小,就是从哪个节点下来的,并用一个direct矩阵记录所来方向,若该节点是从上边节点下来的,就将direct矩阵该节点定为1,否则定为0。
非负矩阵名字定义为matrix,这个matrix矩阵有两条特殊路径,即第一行和第一列,因为第一行的所有节点只能从它左边节点走过来的,而第一列的所有节点都是从它上一个节点走过来的。这样,就能得到第一行每个节点到左上角节点的权值和第一列每个节点到左上角节点的权值。
比如:
(0, 0)(0,1)(0, 2)
(1, 0)(1,1)(1,2)
(2,0)(2, 1)(2,2)
对应的权值为:
1 2 3
4 5 6
2 3 5
节点(0,0)为起始点,节点(2,2)为终止点,从起始点到节点(0,1)的总权值为(0,0)的权值加上(0,1)的权值,从起始点到(0,2)的总权值为(0,0)的权值加上(0,1)的权值加上(0,2)的权值。同理可得(1,0)到起始点的总权值,(2,0)到起始点的总权值。
得到的stat表为
1 3 6
5
7
而(1,1)节点到起始点有两个方向,一个是它的上边,即(0,1)点,一个是它的左边(1,0)点,通过stat表可知,(0,1)点的总权值为3,(1,0)点的总权值为5,因为要获得最短路径,所以我们选最小的权值3在加上当前节点的权值就是当前节点到启始节点的总权值,即为8。为了记录当前权值是从它上边走过来的还是从它左边走过来的,我们还第一了一个direct矩阵,初始化后的direct矩阵为:
0 1 1
0
0
其中,1表示该节点是从它的左边走过来的,0表示该节点是从它上边节点走过来的,在修改stat矩阵时,也应该修改direct矩阵。经过两层循环,就能填充stat矩阵和direct矩阵,填充满后的stat矩阵和direct矩阵为:
stat矩阵:
1 3 6
5 8 12
7 10 15
direct矩阵:
0 1 1
0 0 0
0 1 1
stat矩阵的终止顶点中的权值就是最短路径的权值。
根据direct矩阵,我们能够得到目的顶点(2, 2)是从它左边顶点(2,1)走过来的,因为当前direct值为1(表示从当前顶点左边走过来),而(2,1)是从它左边顶点(2,0)走过来的,而(2,0)是从它上边顶点(1,0)走过来的,而(1,0)又是从它上边(0,0)点走过来的,而(0,0)点就是启始顶点。
由此就得到了最短路径和最短路径权值,代码如下:
# include <iostream># include <vector>using namespace std;void getPath(vector<vector<int> > &matrix, int &value, vector<int> &path_i, vector<int> &path_j){ if(matrix.empty()) return; int rows = matrix.size(); int cols = matrix[0].size(); vector<vector<int> > stat(rows, vector<int> (cols)); // 用来存放已经过节点的总权值 vector<vector<int> > direct(rows, vector<int> (cols)); // 用来存放该节点是从哪个方向来的(1表示从上边,0表示从左边)) int sum = 0; for (int j = 0; j < cols; ++j) // 初始化状态表第一行 { sum += matrix[0][j]; stat[0][j] = sum; direct[0][j] = 1; } sum = 0; for (int i = 0; i < rows; ++i) // 初始化状态表第一列 { sum += matrix[i][0]; stat[i][0] = sum; direct[i][0] = 0; } for (int i = 1; i < rows; ++i) // 填充状态表和方向表 { for (int j = 1; j < cols; ++j) { if (stat[i - 1][j] < stat[i][j - 1]) { stat[i][j] = stat[i - 1][j] + matrix[i][j]; direct[i][j] = 0; } else { stat[i][j] = stat[i][j - 1] + matrix[i][j]; direct[i][j] = 1; } } } value = stat[rows - 1][cols - 1]; // 获取最短路径权值 for (int i = rows -1, j = cols - 1; i >= 0 && j >= 0;) // 获得最短路径 { path_i.push_back(i); path_j.push_back(j); if (direct[i][j] == 1) j--; else i--; }}void printPath(vector<int> path_i, vector<int> path_j) // 打印路径{ for (int i = path_i.size() - 1; i >= 0; --i) { cout << '(' << path_i[i] << ", " << path_j[i] << ')' << endl; }}int main(void){ int matrix_temp[6][7] = {{0, 2, 8, 3, 7, 9, 6}, {5, 3, 7, 9, 6, 8, 1}, {3, 9, 2, 9, 8, 7, 6}, {8, 8, 1, 6, 9, 6, 8}, {3, 2, 9, 8, 7, 7, 1}, {4, 2, 9, 6, 5, 3, 9}}; vector<vector<int> > matrix; int rows = 6; int cols = 7; for (int i = 0; i < rows; ++i) { vector<int> temp; for (int j = 0; j < cols; ++j) { temp.push_back(matrix_temp[i][j]); } matrix.push_back(temp); temp.clear(); } vector<int> path_i; // 用来存放经过的节点的行号 vector<int> path_j; // 用来存放经过的节点的列号 int value; // 用来存放最短路径的权值 getPath(matrix, value, path_i, path_j); cout << "value is " << value << endl; cout << "path: " << endl; printPath(path_i, path_j);}
若有不对之处,敬请指正。
- 编程-从矩阵左上角走到右下角
- 从矩阵左上角到右下角的最大值
- 输出从矩阵左上角到右下角的所有路径
- 计算一个矩阵从左上角到右下角和最大
- 矩阵中从左上角到右下角的路径条数
- (hdu step 3.2.8)命运(简单DP:求从左上角走到右下角的最大值)
- 201301 JAVA 题目2-3级(走网格,从左上角到右下角)
- 控件从左上角移动到右下角
- 经典面试题——从矩阵的左上角到右下角有多少种方法。
- 求在m*n矩阵当中,从左上角出发到右下角有多少种方法
- 【DP】在矩阵中,选择一条从左上角到右下角、经过数字之和最大的路径
- 动态规划求解从矩阵左上角到右下角的最大受益问题
- 矩阵中从左上角到右下角最短路径(五种方法)
- Test1_N*N矩阵从左上角到右下角路径和的最大值
- 计算一个矩阵从左上角到右下角和最大(DFS)
- python实现从二维矩阵左上角到右下角的出路数寻找
- 编程题:动态规划---从左上角到右下角的价值最大的路径
- 从矩阵左上角至右下角(无权值)问题
- muduo网络框架分析
- How I hacked plot.ly by exploiting an SVG vulnerability in plotly.js
- zookeeper实践(二) 伪分布式部署和配置
- hadoop 2.6.4 的安装配置 Ubuntu16.04
- CSS布局第一节课
- 编程-从矩阵左上角走到右下角
- JS函数中带与不带括号的区别
- android去掉标题栏的几种方法
- Hacked: Investigating An Intrusion On My Server
- 读取纯真IP数据库C++源代码
- IOS-- UIView中的坐标转换
- 安卓项目知识小结系列——2016年9月1日
- 逐梦旅程-2016-09-01
- eclipse中使用svn(详细)