题目描述
给定一个m行n列的数字矩阵,计算从左到右走过该矩阵且经过的方格中整数最小的路径。一条路径可以从第1列的任意位置出发,到达第n列的任意位置,每一步为从第i列走到第i+1列的相邻行(水平移动或沿45度斜线移动)。第1行和最后一行看作是相邻的,即应当把这个矩阵看成是一个卷起来的圆筒。
两个略有不同的5行6列的数字矩阵的最小路径如图所示,只有最下面一行的数不同。右边矩阵的路径利用了第 1行与最后一行相邻的性质。
输入格式
包含多个矩阵,每个矩阵的第 1行为两个数 m和n,分别表示矩阵的行数和列数,接下来的mXn个整数按行优先的顺序排列,即前n个数组成第1行,接下来的n个数组成第2行,以此类推。相邻整数间用一个或多个空格分隔,注意这些数不一定是正数。在输人中可能有一个或多个矩阵描述,直到输人结束。每个矩阵的行数在1到10之间,列数在1到100之间。
输出格式
对每个矩阵输出两行,第1行为最小整数之和的路径,路径由n个整数组成,表示路径经过的行号,如果这样的路径不止一条,输出字典序最小的一条。
样例
输入
5 6
3 4 1 2 8 6
6 1 8 2 7 4
5 9 3 9 9 5
8 4 1 3 2 6
3 7 2 8 6 4
输出
1 2 3 4 4 5
16
题解
#include<iostream>
#include<vector>
#include<limits>
#include<algorithm>
using namespace std;
const int M = 20;
const int N = 100;// 定义常量M和N,分别表示预定义的数组的最大行数和列数
const int INF = numeric_limits<int>::max();// 定义一个无穷大值,用于表示无穷大路径长度
int mymin(int a, int b, int c, int& idx) // 函数返回三个参数中的最小值引用参数,更新引用的idx值
{
int n_min = a;
idx = -1;
if (b < n_min)
{
n_min = b;
idx = 0;
}
if (c < n_min)
{
n_min = c;
idx = 1;
}
return n_min;
}
int main()
{
int m, n;
cin >> m >> n;
int arr[M][N], mypath[M][N];
int last_path;//存储最短路径
for (int i = 0; i < m; ++i)
{
for (int j = 0; j < n; ++j)
{
cin >> arr[i][j];
mypath[i][j] = -1; // 初始化mypath数组为-1,表示无效的路径索引
}
}
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
int idx;// 定义一个索引变量用于存储最小路径的索引值
arr[j][i] += mymin(arr[(j - 1 + m) % m][i - 1], arr[j][i - 1], arr[(j + 1) % m][i - 1], idx);
mypath[j][i] = (j + idx + m) % m;
}
}
int min_path = INF;
for (int i = 0; i < m; ++i)//动态规划计算到达每个格子的最短路径长度
{
if (arr[i][n - 1] < min_path)
{
min_path = arr[i][n - 1];
last_path = i;
}
}
vector<int> path;
int current_path = last_path;
for (int j = n - 1; j >= 0; --j)
{
path.push_back(current_path);// 将当前路径添加到path的尾部
current_path = mypath[current_path][j];// 更新当前路径
}
reverse(path.begin(), path.end());
cout << endl;
for (int i = 0; i < path.size(); ++i)
{
cout << path[i]+1 ;
if (i < path.size() - 1) cout << " ";
}
cout << endl;
cout << min_path << endl;
return 0;
}
输出结果
小结
开始我简单的写了一个贪心算法的程序,但是我很快发现我的输出结果与样例输出结果不同。对于算法来说我认为我的程序本身是没有问题的,只是输出结果不是最优解,而实验样例的输出是最优解。众所周知贪心算法并不总是能够得到问题的最优解,而是得到一个接近最优解的结果。为了实现样例输出,我决定重新编写代码,采用DP实现。