紫书上的例题,我们令dp【i】【j】为从表格i,j点开始到最后一列的最小花费。由于还需要输出字典序,所以每一个点我们都要得到它能到下一列哪三行,对于第0行和第n-1行特殊处理,然后将这三行排序,从最小的开始检验,如果符合条件则更新,这样就可以处理相等的情况,并且字典序是最小的。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<stack>
#include<queue>
using namespace std;
#define eps 1e-7
const int maxn = 105;
const int maxm = 10005;
const int INF = 0x3f3f3f3f;
int n, m;
int dp[maxn][maxn], nx[maxn][maxn], G[maxn][maxn];
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
scanf("%d", &G[i][j]);
}
}
for(int i = 0; i < n; i++) {
dp[i][m - 1] = G[i][m - 1];
}
for(int j = m - 2; j >= 0; j--) {
for(int i = 0; i < n; i++) {
dp[i][j] = INF;
int row[3] = {i - 1, i, i + 1};
if(i == 0)
row[0] = n - 1;
if(i == n - 1)
row[2] = 0;
sort(row, row + 3);
for(int k = 0; k < 3; k++) {
int d = dp[row[k]][j + 1] + G[i][j];
if(dp[i][j] > d) {
dp[i][j] = d;
nx[i][j] = row[k];
}
}
}
}
int Min = INF, key;
for(int i = 0; i < n; i++) {
if(dp[i][0] < Min) {
Min = dp[i][0];
key = i;
}
}
for(int i = 0; i < m; i++) {
printf("%d%c", key + 1, i == m - 1 ? '\n' : ' ');
key = nx[key][i];
}
printf("%d\n", Min);
}
return 0;
}