题意:
给一个n行m列的整数矩阵,从第一列任何一个位置出发每次往右、右上或右下走一格,最终到达最后一列。要求经过的整数之和最小。整个矩阵是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行。
输出路径上每行的行号。多解时输出字典序最小的。
解析:
给一个n行m列的整数矩阵,从第一列任何一个位置出发每次往右、右上或右下走一格,最终到达最后一列。要求经过的整数之和最小。整个矩阵是环形的,即第一行的上一行是最后一行,最后一行的下一行是第一行。
输出路径上每行的行号。多解时输出字典序最小的。
解析:
从后往前逆推,dp[i][j]记录,到(i,j)当前整数和最小,再开一个next数组用于保存路径。
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 105;
const int INF = 0x3f3f3f3f;
int grid[N][N];
int next[N][N], dp[N][N];
int m,n;
int main() {
while( scanf("%d%d",&n,&m) != EOF) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
scanf("%d",&grid[i][j]);
}
}
memset(dp,0,sizeof(dp));
int ans = INF , first = 0;
for(int j = m-1; j >= 0; j--) { //逆推
for(int i = 0; i < n; i++) {
if(j == m-1) {
dp[i][j] = grid[i][j];
}else {
int rows[3] = {i-1, i, i+1};
if(i == 0) { //边界
rows[0] = n-1;
}
if(i == n-1) {
rows[2] = 0;
}
sort(rows,rows+3);
dp[i][j] = INF;
for(int k = 0; k < 3; k++) { //求当前所花费的最少步数
int v = dp[rows[k]][j+1] + grid[i][j];
if(v < dp[i][j]) {
dp[i][j] = v;
next[i][j] = rows[k];
}
}
}
if(j == 0 && dp[i][j] < ans) {
ans = dp[i][j];
first = i;
}
}
}
printf("%d",first+1);
int i = next[first][0] , j = 1;
while( j < m) {
printf(" %d",i+1);
i = next[i][j];
j++;
}
printf("\n%d\n",ans);
}
return 0;
}